ReactJS Hooks 总结

Hooks 定义

Hook 就是钩子的意思。为了在函数组件中使用类组件的生命周期、状态管理等一些类组件特性,所以引入了 hooks.
需要注意的是:在类组件中是不能够使用hooks的。

Hooks 使用规则

  • Hooks只能在顶层调用,不能在循环、条件判断或者嵌套函数中调用hook函数。
// 错误写法 
if(a===b){
  useEffect(()=>{
    //...
  },[...])
}
  • 只能在函数组件中使用hooks,不能在类组件中使用
  • 可以使用 eslint-plugin-react-hooks插件规范hooks代码

Hooks 优缺点

优点

  • 代码容易复用(可以自定义useState)
  • 代码可读性强。代码好看些,每个功能都在函数中代码量少
  • 组件层级变少
  • 不需要考虑this 的指向问题

缺点

  • 响应式的 useEflect , useCalbask 的作用、第二个参数(依赖项数组)的改变时机不容易把握。
  • 状态不同步,不在同一个 ui 线程,同一个变量,会显示不同的值。可以使用 useRef 改善。
  • 状态管理容易出错
  • 需要了解所有 hooks 函数

函数列表

useState

  • 用来声明状态变量,类似类组件class 中的this.setState({a:‘abc’})。而且函数的渲染每次都是独立的(异步),这也就是 Capture Value 特性
  • 示例
// 定义
const [nameState, setName] = useState("");// useState 的参数为设定的默认值
const [age, setAge] = useState(1);
// 使用
setName("ABC");
setAge(25);
  • 点击按钮改变nameState值,当回车 Enter(或者不在同一个线程中,初始时注册的方法等)提交时,获取 nameState 值,这时发现nameState还是默认的初始值。例如:点击按钮提交和按回车键提交,点击按钮提交是可以获取到值的,按回车键提交获取值失败。
  • 解决方法:
    • 方法一
const [nameState,setName]=useState();
const lastNameState = useRef(nameState);
// 改变 lastNameState 值 
useEffect(()=>{
  lastNameState.current= nameState;
}[nameState]);
// 点击按钮时,调用setName 
const onClick=(e)=>{
  setName(e.currentTarget.value)
}
  • 方法二
useEffect(()=>{
  setName(name)
},[name]);
//点击按钮时,发送一个action,改变reducer 的state值 
const onClick=(e)=>{
  putName(e.currentTarget.value)
}
//...
// Action
export function putName(name){
  return{
    type:"CHANGE_NAME", 
    payload: { name }
  }
}

useEffect

  • 网上都叫其副作用,我也不明白为啥都叫副作用 ♂️,我更倾向于叫响应。
  • 其替代类组件声明周期函数: componentDidMount、componentWillUnmount、componentDidUpdate。
  • 示例
// componentDidMount || componentWillUnmount
useEffect(()=>{
// componentDidMount
// ...

// componentWillUnmount 
return ()=>{
  //...
},[]);

// componentDidMount || componentDidUpdate 
useEffect(()=>
  setName(name)
),[name]);// 从父组件传递过来的name,当name 发生变化时,更新nameState

useContext

  • 用来处理多层级传递数据,减少组件的嵌套。
  • 示例
function Children(){
  const color = useContext(colorContext);
  return <div>{color}</div>
}

function Parent(){
  return <Children/>
}

const colorContext = createContext("gray");// React.createContext();
function App(){
  return (
    <colorContext.Provider value={"red"}>
      <Parent/>
    </colorContext.Provider>
  )
}

useReducer

  • 可以看成是react-redux 使用方式的缩小版。不能使用redux 提供的中间件。
  • 可以看成是useState 的替代方案
  • useReducer(reducer, initialState, init())。reducer函数,接收state和action; initialState是需要设定的state的初始值;init()是通过方法来初始化state,这样可以情性的创建初始state。
  • 示例
const initialState =0;
const init = (v) =>{
    return v;
}

const testReducer =(state, action)=>{
    switch(action){
        case "add":
            return state+1; 
        case"sub":
            return state-1; 
        case "reset":
            return init(action.payload); 
        default:
            return state;
    
    }
}

const[count, calculationDispatch]= useReducer(testReducer, initialState);
// const[count, calculationDispatch] = useReducer(testReducer, initialState, init); 
return(
    <div>
        <div>{count}</div>
        <button onClick={()=>calculationDispatch("add")}>ADD</button>
        <button oClick={()=>calculationDispatch("sub")}>SUB</button>
        <button oClick={()=>calculationDispatch({type: "reset",payload:initialState})}>RESET</button>
    </div>
)

useCallback

  • 获得一个记忆函数,避免在某些情况下子组件的重复渲染。一般用来做性能优化。
  • useCallback 返回的是一个函数
  • useCallback(function,[…])。两个参数,第一个参数是需要记忆的画数,第二个参数是当数组内的值发生变化了,才执行function。
  • 示例
const [text, setText] = useState(""); 
const submit = useCallback(()=>{
    console.log(text)
}, [text]);

return(
    <div>
        <input value={text} onChange={(e)=>setText(e.target.value)}/>
        <button onClick={submit}>Submit</button>
    </div>
)

useMemo

  • 获得一个记忆组件,适用于返回确定的值
  • 类似useCallback,但是useCallback返回的是需要执行的函数,而useMemo 返回的是执行函数返回的值
  • 示例
const [text, setText] = useState(""); 
const textMemo = useMemo(()=>{
    return text+"time"
}, [text]);
return(
    <div>
        <input value= {text} onChange={(e)=>setText(e.target.value)}/>
        <input value={textMemo}/>
    </div>
)

useRef

  • 生成对DOM对象的引用。
  • 类似于 createRef,但是它是真正的引用,而不是把值copy 过去。
  • 与useState很像,可以把它看成是render的全局变量,而useState是每个render中局部变量; useRef.current 不会触发Ul的重新渲染,而useState会触发Ul的重新渲染。
  • 示例
const [name, setName] = useState("");
const nameRef = useRef(name);
const submit =() =>{
    setName(nameRef.current);
}
return(
    <div>
        <p>{name}</p>
        <div>
            <input ref ={nameRef}/> 
            <button onClick={submit}>Submit</button>
        </div>
    </div>
)

useImperativeHandle

  • 穿透Ref,用于父组件获取子组件的引用
  • 示例
function ChildInputComponent(props, ref){
    const inputRef = useRef(null);
    useImperativeHandle(re, ()=>inputRef.current); 
    return(
        <div>
            <input name="input1" ref={inputRef} placeholder="yes"/>
            <input name="input1" placeholder="nonono"/>
        </div>
    )
}

const ChildInput = forwardRef(ChildInputComponent);
function App(){
    const inputRef = useRef(null);
    useEffect(()=>{
        inputRef.current.focus()
    },[]); 
    
    return(
        <div>
            <ChildInput ref={inputRef}/>
        </div>
    )
}

useLayoutEffect

  • 同步执行,在页面完全渲染完成后,操作 dom, 会优于 useEffect 异步触发函数。

其他

memo

  • 用来包裹函数式组件的
  • 当用React.memo包裹组件时,当组件内的useState或useContext 发生变化时,才会重新渲染面面。
  • memo(Component, propsAreEqual(preProps, nextProps));第一个参数为函数组件,第二个参数为比较规则,若不传递则默认为props 浅比较。

forwardRef

  • 主要用来进行DOM 穿透的
  • 示例
const AButton = React.forwardRef((props, ref)=>(
    <button ref={ref} {...props}>
    {props.children}</button>
))

class BButton extends React.Component{
    this.testRef = React.createRef();
    onClick =()=>{
        // 打印出 AButton 中button 的信息 
        console.log(this.testRef.current)
    };

    render(){
        return(
            <div>
                <AButton ref = {this.testRef} onClick={onClick}>AButtan</AButton>
            </div>
        )
    }

}

总结

这里只罗列了hooks 函数的基本用法,想要更深层次的掌握react 的知识,需要不断的去实践。只有在不断的使用各种技巧、各种功能,才会越发的了解掌握更深入的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值