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自定义Hook

    详解React自定义Hook

    在React项目中,我们经常会使用到React自带的几个内置Hooks,如 useState,useContext和useEffect。虽然在React中找不到这些 Hooks,但React提供了非常灵活的方式让你为自己的需求来创建自己的自定义Hooks,想了解更多的,欢迎阅读本文
    2023-04-04
  • React Native之TextInput组件解析示例

    React Native之TextInput组件解析示例

    本篇文章主要介绍了React Native之TextInput组件解析示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • 浅谈react受控组件与非受控组件(小结)

    浅谈react受控组件与非受控组件(小结)

    本篇文章主要介绍了浅谈react受控组件与非受控组件(小结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • React中遍历数组生成标签问题

    React中遍历数组生成标签问题

    这篇文章主要介绍了React中遍历数组生成标签问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • 详解React 的数据流和生命周期

    详解React 的数据流和生命周期

    这篇文章主要介绍了React 的数据流和生命周期,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • React项目经验总结及遇到的坑

    React项目经验总结及遇到的坑

    这篇文章主要介绍了React项目经验总结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • 详解关于react-redux中的connect用法介绍及原理解析

    详解关于react-redux中的connect用法介绍及原理解析

    本篇文章主要介绍了详解关于react-redux中的connect用法介绍及原理解析,非常具有实用价值,需要的朋友可以参考下
    2017-09-09
  • 使用react+redux实现计数器功能及遇到问题

    使用react+redux实现计数器功能及遇到问题

    使用redux管理数据,由于Store独立于组件,使得数据管理独立于组件,解决了组件之间传递数据困难的问题,非常好用,今天重点给大家介绍使用react+redux实现计数器功能及遇到问题,感兴趣的朋友参考下吧
    2021-06-06
  • react+axios实现github搜索用户功能(示例代码)

    react+axios实现github搜索用户功能(示例代码)

    这篇文章主要介绍了react+axios实现搜索github用户功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • 详解如何封装和使用一个React鉴权组件

    详解如何封装和使用一个React鉴权组件

    JavaScript 和 React 提供了灵活的事件处理机制,特别是通过利用事件的捕获阶段来阻止事件传播可以实现精细的权限控制,本文将详细介绍这一技术的应用,并通过实践案例展示如何封装和使用一个 React 鉴权组件,需要的可以参考下
    2024-03-03

最新评论