关于javascript:关于React-hooks获取不到最新值得分析

41次阅读

共计 1769 个字符,预计需要花费 5 分钟才能阅读完成。

最近在做个需要,需要有个比较复杂的页面,用 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 总是返回雷同的援用

正文完
 0