React Hooks概览

Posted 前端e站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Hooks概览相关的知识,希望对你有一定的参考价值。

Hook 是向下兼容的。本文章为有经验的 React 用户提供一个对 Hook 的概览。

State Hook

这个例子用来显示一个计数器。当你点击按钮,计数器的值就会增加:


import React,  useState  from 'react';
function Example() 
  // 声明一个叫 “count” 的 state 变量。
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked count times</p>
      <button onClick=() => setCount(count + 1)>
        Click me
      </button>
    </div>
  );

在这里,useState 就是一个 Hook。我们在一个function组件里调用它来添加内部state。React将会在重新渲染的过程中保存这个state。useState返回了一对结果——状态值和更新该状态值的方法。你可以在一个事件处理中或者任意地方调用它,和在class里调用this.setState是一样的,唯一的区别在于不会把新旧状态合并到一起(下一章会演示useState和this.state的区别)。

唯一传递给useState的参数是初始状态。在上面的例子中,初始状态值就是0。注意到,跟this.setState不同,state并不必须是一个对象。初始状态参数只在第一次渲染的时候被使用到。

声明多个状态变量

可以在一个组件中使用多个State Hook。

function ExampleWithManyStates() 
  // 声明多个 state 变量!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([ text: 'Learn Hooks' ]);
  // ...

数组结构语法可能让我们在调用useState的时候直接声明变量并获得内容。这些变量名不是useState API的一部分。React设定如果你调用了useState多次,在每次渲染的时候次序也是不变的。

什么是Hook?

Hooks是一个方法可以让你在function组件中"勾入"React状态和生命周期。Hooks不能在class里使用——所以它可以让你在没有class的情况下使用React。(我们不推荐把既有组件披星戴月用Hooks重写)

React提供了类似于useState的一些内置Hooks。你甚至可以创建自己的Hooks来在不同的组件之间复用有状态行为。

Effect Hook

我们以前会执行数据获取、订阅或者手工更改DOM的操作。我们把这些叫做"side effects" 因为它们影响到了其他的组件,在渲染的时候不能被执行。

Effect Hook使用了useEffect的API,使function组件增加了执行side effects的能力。它和componentDidMount、componentDidUpdate、componentWillUnmount的目的是一样的,但融合进了同一个API里。


import React,  useState, useEffect  from 'react';

function Example() 
  const [count, setCount] = useState(0);

  // 相当于 componentDidMount 和 componentDidUpdate:
  useEffect(() => 
    // 使用浏览器的 API 更新页面标题
    document.title = `You clicked $count times`;
  );

  return (
    <div>
      <p>You clicked count times</p>
      <button onClick=() => setCount(count + 1)>
        Click me
      </button>
    </div>
  );

当你调用useEffect时,你在告诉React在DOM更新后来执行你的effect方法。Effects在组件内部声明,它们可以存取props和state。默认情况下,React在每次渲染后执行effect方法——包括首次渲染。

Effects也可以返回一个方法来有时候做一些清理操作。比如,这个组件使用effect订阅一位朋友的在线状态,返回一个取消订阅的方法。


import React,  useState, useEffect  from 'react';

function FriendStatus(props) 
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) 
    setIsOnline(status.isOnline);
  

  useEffect(() => 
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => 
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    ;
  );

  if (isOnline === null) 
    return 'Loading...';
  
  return isOnline ? 'Online' : 'Offline';

在这个示例中,React 会在组件销毁时取消对 ChatAPI 的订阅,然后在后续渲染时重新执行副作用函数。(如果传给 ChatAPI 的 props.friend.id 没有变化,你也可以告诉 React 跳过重新订阅。)

跟 useState 一样,你可以在组件中多次使用 useEffect :


function FriendStatusWit

hCounter(props) 
  const [count, setCount] = useState(0);
  useEffect(() => 
    document.title = `You clicked $count times`;
  );

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => 
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => 
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    ;
  );

  function handleStatusChange(status) 
    setIsOnline(status.isOnline);
  
  // ...

Hooks可以让你在组件里把关联的side effect代码块重新组织起来而不是把它们分散在不同的生命周期回调方法里。

Hooks规则

Hooks本质上是javascript的方法,但它们另外有两个规则

  • 只在最外层调用Hooks。不要在循环语句、条件语句或者嵌套方法里调用Hooks。

  • 只在React的function组件里调用Hooks。不要在普通的JavaScript方法里调用(除了你自定义的Hooks)。

搭建你自己的Hooks

有时候我们想要在组件之间重用有状态的逻辑。一般有两种解决方案——高阶组件和render props。自定义Hooks可以让你实现这个功能,而无须在虚拟DOM树里增加更多的组件。

前面我们创建的FriendStatus组件里调用useState和useEffect两个Hooks来订阅一个朋友的在线状态。假设我们现在想要在另一个组件里复用订阅逻辑。

首先我们把逻辑抽取到自定义的Hook里


import React,  useState, useEffect  from 'react';

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;

它将 friendID 作为参数,并返回该好友是否在线:

现在我们可以在两个组件中使用它:


function FriendStatus(props) 
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) 
    return 'Loading...';
  
  return isOnline ? 'Online' : 'Offline';
function FriendListItem(props) 
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style= color: isOnline ? 'green' : 'black' >
      props.friend.name
    </li>
  );

这两个组件的 state 是完全独立的。Hook 是一种复用状态逻辑的方式,它不复用 state 本身。事实上 Hook 的每次调用都有一个完全独立的 state —— 因此你可以在单个组件中多次调用同一个自定义 Hook。

自定义 Hook 更像是一种约定而不是功能。如果函数的名字以 “use” 开头并调用其他 Hook,我们就说这是一个自定义 Hook。 useSomething 的命名约定可以让我们的 linter 插件在使用 Hook 的代码中找到 bug。

你可以创建涵盖各种场景的自定义 Hook,如表单处理、动画、订阅声明、计时器,甚至可能还有更多我们没想到的场景。我们很期待看到 React 社区会出现什么样的自定义 Hook。

其他 Hook

除此之外,还有一些使用频率较低的但是很有用的 Hook。比如,useContext 让你不使用组件嵌套就可以订阅 React 的 Context。


function Example() 
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...

另外 useReducer 可以让你通过 reducer 来管理组件本地的复杂 state。


function Todos() 
  const [todos, dispatch] = useReducer(todosReducer);
  // ...

以上是关于React Hooks概览的主要内容,如果未能解决你的问题,请参考以下文章

React Native Hooks开发指南

React Native Hooks开发指南

React Native Hooks开发指南

React Native Hooks开发指南

理解 React Hooks

浅谈:为什么vue和react都选择了Hooks?