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 值。


相关文章
|
2月前
|
前端开发 JavaScript 开发者
深入理解React Hooks:提升前端开发效率的关键
【10月更文挑战第5天】深入理解React Hooks:提升前端开发效率的关键
|
2月前
|
前端开发 JavaScript
React Hooks 全面解析
【10月更文挑战第11天】React Hooks 是 React 16.8 引入的新特性,允许在函数组件中使用状态和其他 React 特性,简化了状态管理和生命周期管理。本文从基础概念入手,详细介绍了 `useState` 和 `useEffect` 的用法,探讨了常见问题和易错点,并提供了代码示例。通过学习本文,你将更好地理解和使用 Hooks,提升开发效率。
84 4
|
2月前
|
前端开发
深入解析React Hooks:构建高效且可维护的前端应用
本文将带你走进React Hooks的世界,探索这一革新特性如何改变我们构建React组件的方式。通过分析Hooks的核心概念、使用方法和最佳实践,文章旨在帮助你充分利用Hooks来提高开发效率,编写更简洁、更可维护的前端代码。我们将通过实际代码示例,深入了解useState、useEffect等常用Hooks的内部工作原理,并探讨如何自定义Hooks以复用逻辑。
|
2月前
|
前端开发 JavaScript API
探索React Hooks:前端开发的革命性工具
【10月更文挑战第5天】探索React Hooks:前端开发的革命性工具
|
1月前
|
前端开发 JavaScript API
探究 React Hooks:如何利用全新 API 优化组件逻辑复用与状态管理
本文深入探讨React Hooks的使用方法,通过全新API优化组件逻辑复用和状态管理,提升开发效率和代码可维护性。
|
1月前
|
前端开发
深入探索React Hooks:从useState到useEffect
深入探索React Hooks:从useState到useEffect
25 3
|
1月前
|
前端开发 JavaScript
深入探索React Hooks:从useState到useEffect
深入探索React Hooks:从useState到useEffect
|
1月前
|
前端开发 JavaScript 开发者
“揭秘React Hooks的神秘面纱:如何掌握这些改变游戏规则的超能力以打造无敌前端应用”
【10月更文挑战第25天】React Hooks 自 2018 年推出以来,已成为 React 功能组件的重要组成部分。本文全面解析了 React Hooks 的核心概念,包括 `useState` 和 `useEffect` 的使用方法,并提供了最佳实践,如避免过度使用 Hooks、保持 Hooks 调用顺序一致、使用 `useReducer` 管理复杂状态逻辑、自定义 Hooks 封装复用逻辑等,帮助开发者更高效地使用 Hooks,构建健壮且易于维护的 React 应用。
40 2
|
2月前
|
前端开发 开发者
React 提供的其他重要 Hooks
【10月更文挑战第20天】React 提供了一系列强大的 Hooks,除了 `useRef` 之外,还有许多其他重要的 Hooks,它们共同构成了函数式组件开发的基础。
41 6
|
1月前
|
前端开发 JavaScript
React Hooks 深入解析
React Hooks 深入解析
28 0