React Hooks 核心原理与实战
王沛
eBay 中国研发中心资深技术专家
新⼈⾸单¥59.9
861 人已学习
课程目录
已更新 5 讲 / 共 23 讲
0/2登录后,你可以任选2讲全文学习。
开篇词 (1讲)
开篇词 | 全面拥抱 Hooks,掌握最新 React 开发方式
免费
基础篇 (4讲)
01|认识 React:如何创建你的第一个 React 应用?
02|理解 Hooks:React 为什么要发明 Hooks?
03|两个核心Hook:掌握 React 函数组件的开发思路
04|4个常用内置Hooks:解决函数组件中遇到的特定问题
React Hooks 核心原理与实战
15
15
1.0x
00:00/00:00
登录|注册

04|4个常用内置Hooks:解决函数组件中遇到的特定问题

王沛 2021-06-01
你好,我是王沛。这节课我们来继续学习内置 Hooks 的用法。
在上节课你已经看到了 useState 和 useEffect 这两个最为核心的 Hooks 的用法。理解了它们,你基本上就掌握了 React 函数组件的开发思路。
但是还有一些细节问题,例如事件处理函数会被重复定义、数据计算过程没有缓存等,还都需要一些机制来处理。所以在这节课,你会看到其它四个最为常用的内置 Hooks (包括 useCallback、useMemo、useRef 和 useContext)的作用和用法,以及如何利用这些 Hooks 进行功能开发。

useCallback:缓存回调函数

在 React 函数组件中,每一次 UI 的变化,都是通过重新执行整个函数来完成的,这和传统的 Class 组件有很大区别:函数组件中并没有一个直接的方式在多次渲染之间维持一个状态。
比如下面的代码中,我们在加号按钮上定义了一个事件处理函数,用来让计数器加 1。但是因为定义是在函数组件内部,因此在多次渲染之间,是无法重用 handleIncrement 这个函数的,而是每次都需要创建一个新的:
function Counter() {
const [count, setCount] = useState(0);
const handleIncrement = () => setCount(count + 1);
// ...
return <button onClick={handleIncrement}>+</button>
}
你不妨思考下这个过程。每次组件状态发生变化的时候,函数组件实际上都会重新执行一遍。在每次执行的时候,实际上都会创建一个新的事件处理函数 handleIncrement。这个事件处理函数中呢,包含了 count 这个变量的闭包,以确保每次能够得到正确的结果。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《React Hooks 核心原理与实战》,如需阅读全部文章,
请订阅文章所属专栏新⼈⾸单¥59.9
立即订阅
登录 后留言

精选留言(6)

  • 桃翁
    useRef 如果只是用来 在多次渲染之间共享数据,是不是直接可以把变量定义到组件外面,这样也可以达到目的,感觉还更方便一点呢。

    作者回复: useRef 可以保证这个变量只在当前组件的实例中使用。也就是说,如果一个组件页面上有多个实例,比如:
    <div><Timer /><Timer /></div>
    那么组件外的普通变量是被 Timer 共享的,就会产生问题。

    2021-06-01
  • aloha66
    如果通过useMemo,依赖数组是容器组件的state,来优化展示组件的渲染,这个方案可行吗?
     const ItemRender = useMemo(() =><ComA {...props}/>},[state])
    ...
    {ItemRender}
    2021-06-01
  • Sunny
    import React, {
      useCallback,
      useRef,
      useReducer,
    } from 'react';

    const initialState = {time: 0};
    function reducer(state, action) {
      switch (action.type) {
        case 'increment':
          return {time: state.time + 1};
        default:
          throw new Error();
      }
    }

    export default function Timer() {
      console.log('--render--')

      const [state, dispatch] = useReducer(reducer, initialState);
      
      const timer = useRef(null);

      const setIntervalCallback = useCallback( () => {
        dispatch({type: 'increment'});
        console.log('setinterval time:', state.time) //为什么这里的state.time不变?
      }, [state.time]);//这里的state.time变化被监听到了

      const handleStart = useCallback(() => {
        console.log('handlestart')
        timer.current = window.setInterval(setIntervalCallback, 1000);
      }, [timer, setIntervalCallback]);
      
      const handlePause = useCallback(() => {
        console.log('handlePause')
        window.clearInterval(timer.current);
        timer.current = null;
      }, [timer]);
      
      return(
        <div>
          {state.time} seconds.
          <MyStartBtn handleStart={handleStart}/>
          <MyPauseBtn handlePause={handlePause}/>
        </div>
      );
    }

    function StartButton({handleStart}){
      console.log('startButton render --')
      return <button onClick={handleStart}>Start</button>;
    }
    const MyStartBtn = React.memo(StartButton, (prevProps, nextProps) => {
      return prevProps.handleStart === nextProps.handleStart;
    });

    function PauseButton({handlePause}){
      console.log('pauseButton render --')
      return <button onClick={handlePause}>Pause</button>;
    }
    const MyPauseBtn = React.memo( PauseButton, (prev, next) => {
      return prev.handlePause === next.handlePause;
    })

    /*
    console.log打印结果:
    --render--
    startButton render --
    setinterval time: 0
    每秒循环打印上面3行...


    疑问:
    const setIntervalCallback = useCallback( () => {
        dispatch({type: 'increment'});
        console.log('setinterval time:', state.time) //为什么这里的state.time不变?
      }, [state.time]);//这里的state.time变化被监听到了
    */
    2021-06-01
  • cyh41
    是任何场景 函数都用useCallback 包裹吗?那种轻量的函数是不是不需要?
    2021-06-01
  • 满月
    我们能否用 state 去保存 window.setInterval() 返回的 timer 呢?
    我理解的是可以,只是没有 useRef 更优,因为在更新 state 值后会导致重新渲染,而 ref 值发生变化时,是不会触发组件的重新渲染的,这也是 useRef 区别于 useState 的地方。
    2021-06-01
  • Geek_71adef
    1 useState 实现组件共享,考虑到组件之间的通信
    2 state 去保存的话 会造成异步渲染 造成无限循环
    2021-06-01
收起评论
6
返回
顶部