React state结构设计原则示例详解

 更新时间:2023年06月01日 08:36:12   作者:小乌龟快跑  
这篇文章主要为大家介绍了React state结构设计原则示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

React State 结构设计

React 中组件 state 状态管理是组件设计中的难点之一,如何设计state的结构。遵循以下原则可以保障state更新不出现逻辑上的错误,也可以避免不必要的 state 维护:

相关的状态组合成一个group

当每次触发更新的时候需要更新两个state 则这两个state可以尝试合并成一个state【从单个值类型,变成object 或者 Array 等类型】。

import { useState } from 'react';
function ComA() {
  // bad case 
  const [x, setX] = useState<number>(0);
  const [y, setY] = useState<number>(0);
  // good case
  const [position, setPosition] = useState({ x: 0, y: 0 });
  return (
    <div>
      <div style={{
          position: 'absolute',
          backgroundColor: 'red',
          borderRadius: '50%',
          transform: `translate(${x}px, ${y}px)`,
          left: -10,
          top: -10,
          width: 20,
          height: 20,
        }} />
    </div>
    );
}

避免出现竞态的state

也就是说两个或多个 state 存在竞态,同一时刻有且仅有一个是真值。如果存在这种问题,则需要考虑避免当前这种state的结构, 使用不同的值去区分冲突的 state,这样就把多个冲突的state 合并成1个state,区别在于value的变化以及其代表的意义。

import { useState } from 'react';
// bad  case
function ComA() {
  // 表示编辑状态
  const [isWritting, setIsWritting] = useState(true);
  // 表示是否保存
  const [isSave, setIsSave] = useState(fasle);
  // 其他状态
  const [isComplete, setIsComplete] = useState(false);
  return (
    //...
  );
}
// 这中间 isWriting 和 isSave 是冲突的。也就是说两个state存在竞态,有且仅有一个是真值。
// combine mutilate state ingroup 
function ComB() {
  const [status, setStatus] = useState<'writing' | 'save' | 'complete'>('writing');
  return (
    // ...
  );
}

避免多余的state

如果一个 state 可以通过其他 state 的计算得出【.length, 取反异或等】,那么这个 state 就是不需要存在的。

export default function Form() {
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [fullName, setFullName] = useState('');
  function handleFirstNameChange(e) {
    setFirstName(e.target.value);
    setFullName(e.target.value + ' ' + lastName);
  }
  function handleLastNameChange(e) {
    setLastName(e.target.value);
    setFullName(firstName + ' ' + e.target.value);
  }
  return (
    <>
      <h2>Let's check you in</h2>
      <label>
        First name:{' '}
        <input
          value={firstName}
          onChange={handleFirstNameChange}
        />
      </label>
      <label>
        Last name:{' '}
        <input
          value={lastName}
          onChange={handleLastNameChange}
        />
      </label>
      <p>
        Your ticket will be issued to: <b>{fullName}</b>
      </p>
    </>
  );
}
// fullname  完全可以由 firstName 和 lastName 拼接出来,使用单独的 state 来保存计算结果是多余的。

避免重复的状态

如果state存在重复相同的数据时,这部分重复的数据很难保持同步更新。【一般是针对数组项的处理,data 保存在一个state 中,然后又使用一个state保存选中或者编辑某项。这时候data中的数据更新,current 可能会被缓存到旧值】。需要避免这种重复。解决办法【避免保存重复的内容,而是保存找到指定数据的id或者索引】。

import { useState } from 'react';
const defaultData = [
    { title: 'Tom', id: 0 },
    { title: 'Sam', id: 1 },
    { title: 'Dodo', id: 2 },
    { title: 'Piker', id: 3 },
];
function ComA() {
    const [data, setData] = useState(defaultData);
    const [current, setCurrent] = useState(data[0]);
    function handleClick(item) {
      setCurrent(item);
    }
    function handleInput(id, value) {
      const newData = data.map((item)=>{
        if (id === item.id) {
          return { ...item, title: value };
        }
        return item;
      })
    }
  return (
    <>
      <ul>
        {
          data.map((item) => {
            return (
              <li key={item.id}>
                <input value={item.title} onChange= {({target})=>{ handleInput(item.id, target.value); }}/>
                <button onClick={()=>{ handleClick(item) }}>选中</button>
              </li>
            );
          })
        }
      </ul>
      <p>当前选中:{current.title}</p>
     </>
  );
}
// 问题: 当点击 “选中” 按钮后, current 保存了当前 item 的一个引用。接着编辑当前项的title,发现并不会同步到<p>中展示。

解决方法1

细心检查代码能看出来,通过 handleInput 执行时,返回了新的对象更新 data 中的 item。只要稍微修改一下handleInput的代码,同时更新current即可。

function handleInput(id, value) {
      const newData = data.map((item)=>{
        if (id === item.id) {
          // return { ...item, title: value };
          const newItem = { ...item, title: value };
          setCurrent(newItem);
          return newItem;
        }
        return item;
      })
    }

但是这种方式不能一劳永逸,其他函数中再修改其他属性数据,还得增加同样的逻辑。

解决方法2

保存 item 的 id 不要保存重复的数据内容。

import { useState } from 'react';
const defaultData = [
    { title: 'Tom', id: 0 },
    { title: 'Sam', id: 1 },
    { title: 'Dodo', id: 2 },
    { title: 'Piker', id: 3 },
];
function ComA() {
    const [data, setData] = useState(defaultData);
    // 修改
    const [currentId, setCurrentId] = useState(0);
    const currentItem = data.find(({id}) => id === currentId);
    function handleClick({id}) {
      setCurrentId(id);
    }
    function handleInput(id, value) {
      const newData = data.map((item)=>{
        if (id === item.id) {
          return { ...item, title: value };
        }
        return item;
      })
    }
  return (
    <>
      <ul>
        {
          data.map((item) => {
            return (
              <li key={item.id}>
                <input value={item.title} onChange= {({target})=>{ handleInput(item.id, target.value); }}/>
                <button onClick={()=>{ handleClick(item) }}>选中</button>
              </li>
            );
          })
        }
      </ul>
      <p>当前选中:{current.title}</p>
     </>
  );
}

一劳永逸解决问题,保存id。更新的时候组件会自动获取对应的数据项

避免出现过深的嵌套state

深度嵌套的state不便于更新,更新时,需要一层一层的解构,重组成新的嵌套对象。如果可以尝试使用平铺的方式组织state结构。react 进行state更新时,引用类型数据需要使用新的引用结构进行更新【解构复制,修改对应value】,如果嵌套层级过多,更新时解构层级越复杂,容易出问题。

以这些原则作为 state 结构设计方法论,逐步实现性感&合理的 React 组件!

更多关于React state 结构设计原则的资料请关注脚本之家其它相关文章!

相关文章

  • react render props模式实现组件复用示例

    react render props模式实现组件复用示例

    本文主要介绍了react render props模式实现组件复用示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • 基于React.js实现原生js拖拽效果引发的思考

    基于React.js实现原生js拖拽效果引发的思考

    这篇文章主要为大家详细介绍了基于React.js实现原生js拖拽效果,继而引发的一系列思考,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • React中setState使用原理解析

    React中setState使用原理解析

    这篇文章主要介绍了React中的setState使用细节和原理解析,主要包括使用setstate的原因及基本用法,本文通过实例代码给大家详细讲解,需要的朋友可以参考下
    2022-10-10
  • React替换传统拷贝方法的Immutable使用

    React替换传统拷贝方法的Immutable使用

    Immutable.js出自Facebook,是最流行的不可变数据结构的实现之一。它实现了完全的持久化数据结构,使用结构共享。所有的更新操作都会返回新的值,但是在内部结构是共享的,来减少内存占用
    2023-02-02
  • redux工作原理讲解及使用方法

    redux工作原理讲解及使用方法

    这篇文章主要介绍了redux工作原理讲解及使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-11-11
  • Webpack3+React16代码分割的实现

    Webpack3+React16代码分割的实现

    这篇文章主要介绍了Webpack3+React16代码分割的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • react ant-design Select组件下拉框map不显示的解决

    react ant-design Select组件下拉框map不显示的解决

    这篇文章主要介绍了react ant-design Select组件下拉框map不显示的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • React的特征单向数据流学习

    React的特征单向数据流学习

    这篇文章主要为大家介绍了React的特征单向数据流学习,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • 比ant更丰富Modal组件功能实现示例详解

    比ant更丰富Modal组件功能实现示例详解

    这篇文章主要为大家介绍了比ant更丰富Modal组件功能实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • React项目使用ES6解决方案及JSX使用示例详解

    React项目使用ES6解决方案及JSX使用示例详解

    这篇文章主要为大家介绍了React项目使用ES6解决方案及JSX使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12

最新评论