React Hooks 用法详解1

简介: React Hooks 用法详解

React 中提供的 hooks:

  • useState:setState
  • useReducer:setState,同时 useState 也是该方法的封装
  • useRef: ref
  • useImperativeHandle: 给 ref 分配特定的属性
  • useContext: context,需配合 createContext 使用
  • useMemo: 可以对 setState 的优化
  • useCallback: useMemo 的变形,对函数进行优化
  • useEffect: 类似 componentDidMount/Update, componentWillUnmount,当效果为 componentDidMount/Update 时,总是在整个更新周期的最后(页面渲染完成后)才执行
  • useLayoutEffect: 用法与 useEffect 相同,区别在于该方法的回调会在数据更新完成后,页面渲染之前进行,该方法会阻碍页面的渲染
  • useDebugValue:用于在 React 开发者工具中显示自定义 hook 的标签

官网地址:https://react-1251415695.cos-website.ap-chengdu.myqcloud.com/docs/hooks-reference.html#basic-hooks

一、Hooks 初体验

example:

import React, { useState  } from 'react';
function Example() {
    // 声明一个名为“count”的新状态变量
    const [count, setCount] = useState(0);
    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}
export default Example;

useState 就是一个 Hook,可以在我们不使用 class 组件的情况下,拥有自身的 state,并且可以通过修改 state 来控制 UI 的展示。

1、useState状态

语法:

const [state, setState] = useState(initialState)


  • 传入唯一的参数: initialState,可以是数字,字符串等,也可以是对象或者数组。
  • 返回的是包含两个元素的数组:第一个元素,state 变量,setState 修改 state值的方法。

与在类中使用 setState 的异同点:

  • 相同点:在一次渲染周期中调用多次 setState,数据只改变一次。
  • 不同点:类中的 setState 是合并,而函数组件中的 setState 是替换。

使用对比

之前想要使用组件内部的状态,必须使用 class 组件,例如:

import React, { Component } from 'react';
export default class Example extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }
    render() {
        return (
            <div>
            <p>You clicked {this.state.count} times</p>
            <button onClick={() => this.setState({ count: this.state.count + 1 })}>
                Click me
            </button>
            </div>
        );
    }
}

而现在,我们使用函数式组件也可以实现一样的功能了。也就意味着函数式组件内部也可以使用 state 了。

import React, { useState } from 'react';
function Example() {
    // 声明一个名为“count”的新状态变量
    const [count, setCount] = useState(0);
    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}
export default Example;

优化

创建初始状态是比较昂贵的,所以我们可以在使用 useState API 时,传入一个函数,就可以避免重新创建忽略的初始状态。

普通的方式:

// 直接传入一个值,在每次 render 时都会执行 createRows 函数获取返回值
const [rows, setRows] = useState(createRows(props.count));

优化后的方式(推荐):

// createRows 只会被执行一次const [rows, setRows] = useState(() => createRows(props.count));

2、useEffect执行副作用操作

  • effect(副作用):指那些没有发生在数据向视图转换过程中的逻辑,如 ajax 请求、访问原生dom 元素、本地持久化缓存、绑定/解绑事件、添加订阅、设置定时器、记录日志等。
  • 副作用操作可以分两类:需要清除的和不需要清除的
  • 需要清除的,比如开启的定时器,订阅外部数据源等,这些操作如果在组件消亡后不及时清除会导致内存泄漏。
  • 不需要清除的,比如发起网络请求,手动变更 DOM,记录日志等。
  • 原先在函数组件内(这里指在 React 渲染阶段)改变 dom 、发送 ajax 请求以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性
  • useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 具有相同的用途,只不过被合并成了一个 API
  • useEffect 接收一个函数,该函数会在组件渲染到屏幕之后才执行,该函数有要求:要么返回一个能清除副作用的函数,要么就不返回任何内容
  • componentDidMountcomponentDidUpdate 不同,使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕,这让你的应用看起来响应更快。大多数情况下,effect 不需要同步地执行。在个别情况下(例如测量布局),有单独的 useLayoutEffect Hook 供你使用,其 API 与 useEffect 相同。

语法:

1、useEffect(() => { doSomething });
2、useEffect(() => { doSomething },[]);
3、useEffect(() => { doSomething },[count]);

第一个参数为 effect 函数,该函数将在 componentDidMmount 时触发和 componentDidUpdate 时有条件触发(该添加为useEffect 的第二个数组参数)

  • 第二个参数是可选的,根据条件限制看是否触发
  • 如果不传,如语法1,则每次页面数据有更新(如componentDidUpdate),都会触发 effect。
  • 如果为空数组[],如语法2,则每次初始化的时候只执行一次effect(如componentDidMmount)
  • 如果只需要在指定变量变化时触发 effect,将该变量放入数组。如语法3,count只要变化,就会执行effect,如观察者监听
  • 清除副作用
  • 副作用函数还可以通过返回一个函数来指定如何清除副作用,为防止内存泄漏,清除函数会在组件卸载前执行。如果组件多次渲染,则在执行下一个 effect 之前,上一个 effect 就已被清除。
  • 例1、比如window.addEventListener('resize', handleResize);:监听resize等
useEffect(() => {
    window.addEventListener('resize', handleResize);
    window.addEventListener('keydown', onKeyDown);
    window.addEventListener('keyup', onKeyUp);
    return (() => {
      window.removeEventListener('resize', handleResize);
      window.removeEventListener('keydown', onKeyDown);
      window.removeEventListener('keyup', onKeyUp);
    })
  }, [globalRef]);

例2、清除定时器

function Counter(){
    let [number,setNumber] = useState(0);
    let [text,setText] = useState('');
    useEffect(()=>{
        let $timer = setInterval(()=>{
            setNumber(number=>number+1);
        },1000);
        // useEffect 如果返回一个函数的话,该函数会在组件卸载和更新时调用
        // useEffect 在执行副作用函数之前,会先调用上一次返回的函数
        // 如果要清除副作用,要么返回一个清除副作用的函数
       /*  return ()=>{
            console.log('destroy effect');
            clearInterval($timer);
        } */
    });
    // },[]);//要么在这里传入一个空的依赖项数组,这样就不会去重复执行
    return (
        <>
          <input value={text} onChange={(event)=>setText(event.target.value)}/>
          <p>{number}</p>
          <button>+</button>
        </>
    )
}

3、useContext组件之间传值

语法

const value = useContext(MyContext);

之前在用类声明组件时,父子组件的传值是通过组件属性和props进行的,那现在使用方法(Function)来声明组件,已经没有了constructor构造函数也就没有了props的接收,但是也可以直接收,如下:

组件:
<SwitchList dataList={toolsList} isReverse={false}/>
接收:
const SwitchList = ({dataList = null, isReverse = false}: any): React.ReactElement => {
    //TODO
}

React Hooks 也为我们准备了useContext。它可以帮助我们跨越组件层级直接传递变量,实现共享。

一:利用 createContext 创建上下文

import React, { useState , createContext } from 'react';
// 创建一个 CountContext
const CountContext = createContext()
function Example(){
  const [ count , setCount ] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()=>{setCount(count+1)}}>click me</button>
      {/* 将 context 传递给 子组件,context 值由value props决定*/}
      <CountContext.Provider value={count}>
        <Counter/>
      </CountContext.Provider>
    </div>
  )
}
export default Example;

二:使用useContext 获取上下文

对于要接收context的后代组件,只需引入 useContext() Hooks 即可。

强调一点:

useContext 的参数必须是 context 对象本身:

  • 正确:useContext(MyContext)
  • 错误:useContext(MyContext.Consumer)
  • 错误:useContext(MyContext.Provider)

当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 <MyContext.Provider> 的 context value 值。


相关文章
|
1月前
|
前端开发 测试技术 开发工具
探索前端框架React Hooks的优势与应用
本文将深入探讨前端框架React Hooks的优势与应用。通过分析React Hooks的特性以及实际应用案例,帮助读者更好地理解和运用这一现代化的前端开发工具。
|
1月前
|
前端开发 JavaScript
react常用的hooks有哪些?
react常用的hooks有哪些?
41 0
|
7天前
|
缓存 前端开发 JavaScript
React Hooks 一步到位
React Hooks 一步到位
|
1月前
|
存储 前端开发 JavaScript
React Hooks 的替代方案有哪些?
【5月更文挑战第28天】React Hooks 的替代方案有哪些?
28 2
|
1月前
|
前端开发 JavaScript 开发者
React Hooks 的应用场景有哪些?
【5月更文挑战第28天】React Hooks 的应用场景有哪些?
16 1
|
1月前
|
前端开发 JavaScript 开发者
React Hooks 是在 React 16.8 版本中引入的一种新功能
【5月更文挑战第28天】React Hooks 是在 React 16.8 版本中引入的一种新功能
27 1
|
1月前
|
前端开发
React Hooks - useState 的使用方法和注意事项(1),web前端开发前景
React Hooks - useState 的使用方法和注意事项(1),web前端开发前景
|
1月前
|
前端开发
探索React Hooks:一种全新的组件逻辑管理方式
React Hooks是React 16.8版本引入的一项新功能,它改变了我们编写React组件的方式。本文将从Hooks的起源讲起,逐步分析Hooks的优势,并通过具体示例展示Hooks在组件逻辑管理中的应用,旨在帮助读者更好地理解和运用React Hooks。
|
1月前
|
前端开发 API 开发者
React Hooks API:自定义Hooks的创建与使用
【4月更文挑战第25天】本文介绍了React自定义Hooks的创建与使用。自定义Hooks是提升React开发效率的关键工具。
|
1月前
|
前端开发 JavaScript
React Hooks:让你轻松掌握函数组件的状态与管理
React Hooks:让你轻松掌握函数组件的状态与管理