[2021-02-24更新]​React Hook使用要点

2022-07-27 15:45:11 浏览数 (1)

在官网上,Hook简介的章节里,很安抚性地提到,Hook的提出不旨在替换Class创建组件,而是一种可选、100%向后兼容的特性。然而从使用效果的来说,Hook的应用,解决了render props 和高阶组件组织代码所带来晦涩难懂的窘况,让前端代码代码复用的粒度变得更低,代码可读性更高,研发效率自然也更高。我们团队的新代码,基本都在转向Hook,我也不例外,为了快速翻阅资料,整理以下核心信息,方便高效研发。

【关键点一】只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。

可以阅读这个文章来深入理解:https://juejin.cn/post/6844903850567008270

或者原文 https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e

【关键点二】不可以不学习Class Component而直接学习Hook,否则Hook将会显得非常难理解。

此外,只能在 React 的函数组件或者自定义Hook中调用 Hook。不要在其他 JavaScript 函数中调用。

提纲

  • State Hook 直接对标Class Component中state的功能,更新state的值会触发Function Component的重新渲染
  • Effect Hook 对标的是Class Component中的生命周期,处理componentDidMount、componentDidUpdate 和 componentWillUnmount三种生命周期中的附加行为,也就是副作用
  • 自定义 Hook 对标高阶组件和 render props,在组件之间重用一些状态逻辑,也就是交互行为,可以释放非常多的前端人力
  • Context Hook 不使用组件嵌套就可以订阅 React 的 Context
  • Reducer Hook 通过 reducer 来管理组件本地的复杂 state,一种模仿Redux处理state的方案。
  • Ref Hook 参考Class Component中的ref,用于访问子组件

State Hook

样例代码

代码语言:javascript复制
import React,{ useState } from'react';
function Example(){
// 声明一个叫 “count” 的 state 变量。
const [count, setCount]=useState(0);
return(
<div>
<p>You clicked {count} times</p>
<buttononClick={()=>setCount(count  1)}> Click me</button>
</div>
);}

useState 唯一的参数就是初始 state

useState 会返回一对值:当前状态和一个让你更新它的函数;

类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并

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

Effect Hook

样例代码

代码语言:javascript复制
import React,{ useState, useEffect } from'react';
function Example(){
const [count, setCount] = useState(0);
    useEffect(()=>{
// 组件渲染完毕之后,使用浏览器的 API 更新页面标题 
// 相当于 componentDidMount 和 componentDidUpdate:   
document.title =`You clicked ${count} times`;
const token = setInterval(function(){ alert("Hello"); }, 3000);
return ()=>{
// 清理附加到生命周期的行为,相当于 omponentWillUnmount
            clearInterval(token);
        }
    });
return(<div>
<p>You clicked {count} times</p>
<buttononClick={()=>setCount(count  1)}> Click me </button>
</div>);}

跟 class 组件中的 componentDidMount、componentDidUpdate 和 omponentWillUnmount 具有相同的用途,只不过被合并成了一个 API

可以访问到组件的 props 和 state

副作用函数还可以通过返回一个函数来指定如何“清除”副作用。

跟 useState 一样,你可以在组件中多次使用 useEffect,这带来很清晰、粒度很细的属性和行为控制的能力

自定义 Hook

样例代码

代码语言:javascript复制
import React, { useState, useEffect } from 'react';
// 一个自定义个Hook,用于侦听好友是否在线和取消侦听,在其他组件中,通过传入friendID既可以复用这里的行为
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 更像是一种约定而不是功能。如果函数的名字以 “use” 开头并调用其他 Hook,我们就说这是一个自定义 Hook。

创建涵盖各种场景的自定义 Hook,如表单处理、动画、订阅声明、计时器、webSocket的管理等。

Context Hook

样例代码

代码语言:javascript复制
// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 为当前的 theme 创建一个 context(“light”为默认值)。
const ThemeContext = React.createContext('light');
class App extends React.Component {
  render() {
// 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
// 无论多深,任何组件都能读取这个值。
// 在这个例子中,我们将 “dark” 作为当前的值传递下去。
return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}
// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar() {
return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
// 指定 contextType 读取当前的 theme context。
// React 会往上找到最近的 theme Provider,然后使用它的值。
// 在这个例子中,当前的 theme 值为 “dark”。
static contextType = ThemeContext;
  render() {
return <Button theme={this.context} />;
  }
}

接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定

背景知识:Context 提供了一种在组件之间共享全局值的方式,而不必显式地通过组件树的逐层传递 props,是一种比Redux更老的共享数据的方案。

Reducer Hook

样例代码

代码语言:javascript复制
// 计数器案例的 Reducer Hook改写方案
const initialState = {count: 0};

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 (
<>
      Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}> </button>
</>
  );
}

useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。

如果 Reducer Hook 的返回值与当前 state 相同,React 将跳过子组件的渲染及副作用的执行

Ref Hook

样例代码

代码语言:javascript复制
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };
return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

0 人点赞