最近在做个需要,需要有个比较复杂的页面,用React hooks写的组件,因为对这种形式不相熟,导致意想不到的后果,通常都是因为没有获取到最新值得问题;

有时候获取不到最新的state状态值,如下例子:

import React, { useState, useEffect } from 'react';export default function Test() {  const [name, setName] = useState('Kidy');  const say = () => {    console.log('name', name);  };  useEffect(() => {    // 设置name的值为Joy    setName('Joy');    // 1s后打印出name的值,实践上name的最新的值为Joy,冀望输入Joy    setTimeout(() => {      say();    }, 1000);  }, []);  return null;}

后果打印进去的是

name Kidy

所以为什么呢?
咱们改一下这个示例,减少能失常获取name值的形式:

import React, { useState, useEffect } from 'react';export default function Test() {  const [name, setName] = useState('Kidy');  const say = () => {    console.log('name', name);  };  useEffect(() => {    // 设置name的值为Joy    setName('Joy');    // 1s后打印出name的值,实践上name的最新的值为Joy,冀望输入Joy    setTimeout(() => {      say();    }, 1000);  }, []);    // 减少了一个按钮,点击触发say函数的执行  return (    <div>      <button onClick={say}>        按钮      </button>    </div>  );}

点击按钮输入:

name Joy

那么为什么延时函数里执行的say()输入的name不是最新的Joy呢?当调用setName给name从新赋值时,组件从新构建,相当于从新执行了一遍Test函数,外面的局部变量包含namesay会再一次创立并且被赋值,此时namesay曾经是新的值,因为useEffect的第二个参数为空数组,所以第一入参的函数仍然没有扭转,其中的say变量指向的还是上一次创立的say函数(造成了一个闭包),外面保留着上一次的name值,所以输入还是上一次的值Kidy

为什么点击按钮输入的是最新的值JoyTest再次被创立时,构建并返回了最新的DomonClick指向的是当次创立的say函数,也即是蕴含最新name值的say函数作为button的点击执行函数。

再来看一个案例:

import React, { useState, useEffect, useRef } from 'react';export default function Test() {  const [name, setName] = useState('Kidy');  const country = useRef('美国');  const say = () => {    console.log('name', name);    console.log('country', country.current);  };  useEffect(() => {    // 设置name的值为Joy    setName('Joy');    // 这里间接设置为'加拿大'    country.current = '加拿大';    // 1s后打印出name的值,实践上name的最新的值为Joy,冀望输入Joy    setTimeout(() => {      say();    }, 1000);  }, []);  return (    <div>      <button onClick={say}>        按钮      </button>    </div>  );}

延时函数和点击事件输入的country.current的值都是最新的值加拿大,这个又是为什么呢?country用的是useRef函数返回值,其返回的是一个援用,赋值的时候是给country对象属性current赋值,也就是在Test函数从新执行的时候country的指向始终没变,所以无论什么时候什么状况下对同一个援用输入属性值,都是雷同的。

函数组件在从新执行时,useState总是返回一个全新的值,useRef总是返回雷同的援用