10 mins 带你入门 React Hooks

Why Hooks

  1. Function Component 可使用状态
  2. 简化 Class Component 的生命周期
  3. 无需为 this 指向问题伤破脑经
  4. 解决 render props & HOC 嵌套缺陷
  5. 官方爸爸让你学

How to use Hooks

如今开始咱们用建立一个计数器的方式开始学习使用React Hooksjavascript

useState

useState 的用法很简单,传入一个初始 state,返回一个 state 以及修改 state 的函数。html

// useState 返回的 state 是个常量
// 每次组件从新渲染以后,当前 state 和以前的 state 都不相同
// 即便这个 state 是个对象
const [count, setCount] = useState(1)
复制代码

setCount 就至关于 setState ,能够传入一个新的状态或者函数。例如:java

setCount(2)
setCount(prevCount => prevCount + 1)
复制代码

其实 useState 内部能够简单理解为(只是理解):react

// 闭包存储 state 数据
function useState(initialState){
    let state = initialState;
    function setState = (newState, action) => {
        state = newState;
    }
    return [state, setState]
}
复制代码

那接下来编写 Count 组件:redux

function Counter() {
  const [count, setCount] = React.useState(0)
  return (
    <div> Count: {count} <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button> <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button> </div>
  );
}
复制代码

useEffect

如今咱们有了新的需求: 在 count 每次更新的时候打印 count 的值,这时咱们须要用 useEffect 来实现闭包

function Counter() {
  const [count, setCount] = React.useState(0)
  
  React.useEffect(() => {
    console.log(count)
  })
  
  return (
    <div> Count: {count} <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => setCount(count - 1)}>-</button> </div>
  );
}
复制代码

以上在每次从新渲染时, useEffect 就能够实现打印,能够把它看成是 componentDidUpdatecomponentDidMount, 同于 Class Component中的函数

componentDidMount() {
  console.log(count)
}
componentDidUpdate() {
  console.log(count)
}
复制代码

另外它能够返回一个函数,用于解绑一些反作用,功能相似于 componentWillUnmount学习

React.useEffect(() => {
    console.log(count)
    // 注意: 当咱们每次更新计数时,都会先打印 clean 这行 log
    return () => console.log('clean', count)
})
复制代码

为了防止咱们没必要要的渲染,useEffect 加入第二个参数, 只有在 count 改变的时候才会执行。优化

React.useEffect(() => {
    console.log(count)
    // 当咱们每次更新计数时,都会先打印 clean 这行 log
    return () => console.log('clean', count)
}, [count])
复制代码

useReducer

useReduceruseState 的替代方案,主要是为了解决多个 state 子值的问题。(会Redux的一看就会明白)ui

看一下🌰:

// 初始化 state
const initialState = {count: 0};

// 类于 redux 的 reducer
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div> Count: {state.count} /* dispatch 调用 action 操做 */ <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </div>
  );
}
复制代码

useMemo

这是个用于优化的 hook, 返回一个 memoized 值。说白了就是会利用闭包的特性存储上次的参数,若是和此次传入的参数一致就返回以前的结果。这叫作记忆化技术。

下面咱们来看个反🌰:

function WithoutMemo() {
    const [count, setCount] = useState(1);
    const [val, setValue] = useState('');

    function expensive() {
        console.log('compute');
        let sum = 0;
        for (let i = 0; i < count * 100; i++) {
            sum += i;
        }
        return sum;
    }

    return <div> <h4>{count}-{val}-{expensive()}</h4> <div> <button onClick={() => setCount(count + 1)}>+c1</button> <input value={val} onChange={event => setValue(event.target.value)}/> </div> </div>; } 复制代码

这个函数式组件面临的问题就是 expensive 方法无论是 count 仍是 val 改变时都会因为组件的从新渲染, 从新计算。

可是这里的昂贵计算只依赖于count的值,在val修改的时候,是没有必要再次计算的。在这种状况下,咱们就可使用useMemo,只在count的值修改时,执行expensive计算:

// count 若是不变就不会再次执行
const expensive = React.useMemo(() => {
    console.log('compute');
    let sum = 0;
    for (let i = 0; i < count * 100; i++) {
        sum += i;
    }
    return sum;
}, [count]);
复制代码

useCallback

useCallbackuseMemo 很类似,不过它返回的是函数。下面继续看个🌰:

function Parent() {
    const [count, setCount] = React.useState(1);
    const [val, setVal] = React.useState('');

    const callback = React.useCallback(() => {
        return count;
    }, [count]);
    
    return <div>
        <h4>{count}</h4>
        // callback 做为 props 传入
        <Child callback={callback}/>
        <div>
            <button onClick={() => setCount(count + 1)}>+</button>
            <input value={val} onChange={event => setVal(event.target.value)}/>
        </div>
    </div>;
}

function Child({ callback }) {
    const [count, setCount] = React.useState(() => callback());
    
    React.useEffect(() => {
        setCount(callback());
    }, [callback]);
    
    return (
        <div>
            {count}
        </div>
    )
}
复制代码

如今就是有一个父组件,其中包含子组件,子组件接收一个函数做为props;一般而言,若是父组件更新了,子组件也会执行更新;可是大多数场景下,更新是没有必要的,咱们能够借助useCallback来返回函数,而后把这个函数做为props传递给子组件;这样,子组件就能避免没必要要的更新。

useCallback(fn, deps) 至关于 useMemo(() => fn, deps)。

自定义 Hook

经过自定义 Hook,能够将组件逻辑提取到可重用的函数中。

自定义 Hook 是一个函数,其名称以 use 开头,函数内部能够调用其余的 Hook

function useConsoleCount(count) {
  React.useEffect(() => {
    console.log(count)
    // 当咱们每次更新计数时,都会先打印 clean 这行 log
    return () => console.log('clean', count)
  }, [count])
}

function Counter() {
  const [count, setCount] = React.useState(0);
  
  useConsoleCount(count)
  
  return (
    <div> Count: {count} <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => setCount(count - 1)}>-</button> </div>
  );
}
复制代码

结尾

  • 这篇只是简单介绍hook的使用,有错误的地方欢迎指正
  • 关于其余的 hook 可直接阅读官方文档
相关文章
相关标签/搜索