Vue到React迁移笔记(四)Hook

304 阅读3分钟

Hook可以让你在不编写class的情况下使用state或其他React特性。

初识

要解决的问题

  • 使用render props或高阶组件来提取组件的复用性行为会使得你重新组值组件架构并且使你的代码难以理解。React需要更好的共享状态逻辑的途径。
  • 在一个组件中,生命周期钩子函数中同时完成了多个任务比如数据获取与事件监听,这让完全没有逻辑关系的代=代码出现在了同一个函数中。
  • class组件有一些问题:你必须理解this的工作模式,class不能很好压缩,热重载不稳定等。React组件一直更像函数,而Hook使你可以在非class情况下使用更多的React特性。 什么是Hook
  • 是一些可以让你在函数组件中使用state以及生命周期等特性的函数。

规则

  • 你只能在函数组件的最外层调用Hook,不要试图将他们放再循环,判断或子函数中。
  • 不要在非React函数组件中调用Hook。

State Hook

  // 声明一个叫 “count” 的 state 变量。
  const [count, setCount] = useState(0);
  • useState就是一个Hook。
  • 返回一对值:当前的状态+让你更新他的函数,类似于class组件的this.setState。使用数组解构的写法获取返回值。
  • 接受一个参数:state的初始值。
  • 这样生成的state并不再使用this.state,而是直接取参数名{name}
  • 你的更新函数,调用时只需传入一个参数来表示要更改成的值。

Effect Hook

 // 相当于 componentDidMount 和 componentDidUpdate:
 useEffect(() => {
     // 使用浏览器的 API 更新页面标题
     document.title = `You clicked ${count} times`;  
 });
  • 在React组件中执行数据获取,事件订阅或手动修改dom,这些操作被称为副作用。
  • useEffect就是一个副作用Hook,它给予函数组件操作副作用的能力。他与class组件中生命周期钩子函数具有相同的用途,只不过被合并成了一个API。
  • React会在每次更新渲染后调用副作用函数,包括第一次渲染。你可以认为是componentDidMount+componentDidUpdate,通过在useEffect中return一个函数来清楚副作用,你返回的函数相当于componentWillUnmount
  • 尽量每个hook只完成一个逻辑任务,解决了class生命周期中一个钩子函数包含了不相干的逻辑的问题。
  • 当同一轮渲染间隔有多个state时,Effect Hook不会调用,这和生命周期钩子有相同特性。这个功能被继承再里setState中实现。

自定义Hook

在class组件中,我们使用高阶组件和render props来提取组件间可共用部分。自定义Hook的思想为函数组件提供了实现方式。我们约定函数名为useSomethingStatus来表示这是一个自定义Hook。

//以下代码实现了一个自定义Hook,你可以调用它来返回一个state值,他会根据自定义hook内的逻辑发生改变。
function useFriendStatus(friendID) {  
  const [isOnline, setIsOnline] = useState(null);
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });
  return isOnline;
}
//这个组件使用了上述的自定义Hook,生成了一个state,组件内没有定义state更新逻辑,自定义hook内的内容会实现你对这个state的逻辑。
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);
  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

useContext

  • 接受一个context对象并返回此context的值。他来自于最近的provider中的value props