详解React如何优雅地根据prop更新state值

 更新时间:2023年11月14日 08:22:58   作者:晓得迷路了  
这篇文章主要为大家详细介绍了React如何优雅地实现根据prop更新state值,文中的示例代码讲解详细,具有一定的参考价值,感兴趣的小伙伴可以了解下

快速总结:

场景

开发 React 组件中,有时会碰到同步状态的问题,就是当 prop 变化时调整组件的 state 值。

比如以下这个场景:一个下拉组件 Select 内置了两组选项内容,支持通过 type 来选择,同时也支持传入 options 参数自定义选项内容。

代码实现方面,内部维护一个 innerOptions,外部参数 typeoptions 通过 useEffect 来同步,相关代码如下:

import React, { useState, useEffect } from "react";
import { Flex, Space, Select } from "antd";

function MySelect({ value, onChange, type, options }) {
  const optionsList = [[
    { value: "dog", label: "小狗" },
    { value: "cat", label: "小猫" },
  ], [
    { value: "banana", label: "香蕉" },
    { value: "apple", label: "苹果" },
  ]]
  const [innerOptions, setInnerOptions] = useState(options || optionsList[type] || [])

  useEffect(() => {
    if (type !== undefined) {
      setInnerOptions(optionsList[type])
    }
  }, [type]);

  useEffect(() => {
    if (options !== undefined) {
      setInnerOptions(options)
    }
  }, [options])

  return (
    <Space direction="vertical">
      {`你选择了:${innerOptions.find((item) => item.value === value)?.label}`}
      <Select
        style={{ width: 120 }}
        value={value}
        onChange={onChange}
        options={innerOptions}
      />
    </Space>
  );
}

正常使用这个组件时一切都是正常的。

问题出现

不过当你需要在一个 Select 组件中切换 type 时,就会出现一个问题,切换过程中间会闪现过一个 undefined

import React, { useState } from "react;
import { Flex, Space } from "antd";
import MySelect from "./MySelect";

function App() {
  const [value, setValue] = useState("dog");
  const [type, setType] = useState(0);

  const handleChange = (newVal) => {
    setValue(newVal);
  };

  const handleChangeType = (e) => {
    setType(e.target.value);
    setValue(e.target.value === 0 ? 'dog' : 'banana')
  }

  return (
    <div className="App">
      <Flex gap="middle" vertical>
        <Radio.Group onChange={handleChangeType} value={type}>
          <Radio value={0}>动物</Radio>
          <Radio value={1}>水果</Radio>
        </Radio.Group>
        <MySelect type={type} value={value} onChange={handleChange} />
      </Flex>
    </div>
  );
}

问题的原因是切换选项时,value 值是直接更新的,而 innerOptionsuseEffect 中更新的,也就是中间会出现一次 value 为新值,而 innerOptions 为旧值的渲染。

寻找解决方案

既然找到了原因,就开始想办法处理这个问题。

useLayoutEffect

第一时间想到了用 useLayoutEffect 能否解决, useLayoutEffect 在 react 文档中说明是在将内容真正渲染到屏幕前调用,并且会阻塞浏览器重绘。

将 useEffect 全部改成 useLayoutEffect。

useLayoutEffect(() => {
    if (type !== undefined) {
      setInnerOptions(optionsList[type])
    }
}, [type]);

useLayoutEffect(() => {
    if (options !== undefined) {
      setInnerOptions(options)
    }
}, [options])

可以看到不会出现 undefined 的情况了。

useLayoutEffect 会降低性能。在可能的情况下,最好使用 useEffect。

不过官方文档有提到 useLayoutEffect 会降低性能,再看看是否有更好的方案。

react 最佳实践

prop 改变后 state 同步这个在 react 文档中有编码建议。

官方推荐不要使用 useEffect,在函数中直接调整 state 值。

const [innerOptions, setInnerOptions] = useState(options || optionsList[type] || [])
const [prevType, setPrevType] = useState(type);
const [prevOptions, setPrevOptions] = useState(options);

if (prevType !== type) {
    setPrevType(type);
    setInnerOptions(optionsList[type])
}

if (prevOptions !== options) {
    setPrevOptions(type);
    setInnerOptions(options)
}

上面的代码比起使用 useEffect 的代码可能并不常见。

当你在组件渲染函数中直接更新组件时,React 会丢弃返回的 JSX 并立即重新渲染。不过为了避免非常缓慢的级联重试,React 只允许你在组件函数中更新同一组件的状态。

也就是说 value 为新值,而 innerOptions 为旧值的渲染被丢弃了,所以不会出现 undefined 的情况,问题也得到了解决。

总结

正常情况下,我们使用 useEffect 来将 prop 更新到 state 是没问题的。不过在有界面渲染的情况下,可能会有 bug 出现,这时需要使用 useLayoutEffect 或者直接在组件渲染函数中更新 state 值。

其实根据 prop 更新 state 在非必要的情况下尽量不要出现,优先考虑在渲染函数中直接根据 prop 计算状态或者通过 key 值重新渲染整个组件

例如以下方式处理 innerOptions:

// 直接根据 prop 计算状态
const innerOptions = optionsList[type] || options || []

以上就是详解React如何优雅地根据prop更新state值的详细内容,更多关于React更新state值的资料请关注脚本之家其它相关文章!

相关文章

  • React 全面解析excel文件

    React 全面解析excel文件

    这篇文章主要介绍了React 全面解析excel文件,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • TypeScript在React项目中的使用实践总结

    TypeScript在React项目中的使用实践总结

    这篇文章主要介绍了TypeScript在React项目中的使用总结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • react的严格模式和解决react useEffect执行两次问题

    react的严格模式和解决react useEffect执行两次问题

    文章总结:本文详细探讨了React中useEffect执行两次的问题,主要归因于React的严格模式,严格模式在开发模式下会故意重复调用一些生命周期方法,以帮助开发者发现潜在的问题,包括不安全的生命周期、过时的ref API、废弃的findDOMNode方法、意外的副作用等
    2025-01-01
  • 用react实现一个简单的scrollView组件

    用react实现一个简单的scrollView组件

    这篇文章主要给大家介绍一下如何用 react 实现一个简单的 scrollView组件,文中有详细的代码示例,具有一定的参考价值,需要的朋友可以参考下
    2023-07-07
  • React教程之Props验证的具体用法(Props Validation)

    React教程之Props验证的具体用法(Props Validation)

    这篇文章主要介绍了React教程之Props验证的具体用法(Props Validation),非常具有实用价值,需要的朋友可以参考下
    2017-09-09
  • 浅谈React 中的浅比较是如何工作的

    浅谈React 中的浅比较是如何工作的

    React 中浅比较的概念无处不在,它在不同的流程中起着关键的作用,本文主要介绍了React 中的浅比较是如何工作的,具有一定的参考价值,感兴趣的可以了解一下
    2022-04-04
  • React实现轮播图效果

    React实现轮播图效果

    这篇文章主要为大家详细介绍了React实现轮播图效果,使用react-slick组件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • React倒计时功能实现代码——解耦通用

    React倒计时功能实现代码——解耦通用

    这篇文章主要介绍了React倒计时功能实现——解耦通用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • React实现阿里云OSS上传文件的示例

    React实现阿里云OSS上传文件的示例

    这篇文章主要介绍了React实现阿里云OSS上传文件的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • React+Vite中利用Fetch将CSV数据转成JSON字符串

    React+Vite中利用Fetch将CSV数据转成JSON字符串

    在一些小型项目中,前端可能需要直接处理 CSV 文件数据,将其转换为 JSON 字符串后再进行逻辑操作和展示,本文将会介绍两种方法,需要的朋友可以参考下
    2025-12-12

最新评论