React基础 第十七章(良好的State结构)

在React中,选择合适的state结构是构建高效、可维护应用程序的关键。本文将深入探讨如何根据React官方文档的建议来选择state结构,并提供实用的技巧、示例代码以及注意事项。

合并关联的State

当你发现自己在多个state变量上执行相同的操作时,最好将它们合并为一个单独的state变量。

技巧:

  • 使用对象或数组来组合相关的state。
  • 当更新state时,确保更新所有相关字段。

示例:

jsx 复制代码
const [position, setPosition] = useState({ x: 0, y: 0 });

function handlePointerMove(e) {
  setPosition({ x: e.clientX, y: e.clientY });
}

注意事项:

  • 当使用对象作为state时,更新单个字段时不要忘记保留其他字段。
  • 或者使用immer

正确代码:

jsx 复制代码
setPosition(prevPosition => ({ ...prevPosition, x: 100 }));

错误代码:

jsx 复制代码
setPosition({ x: 100 }); // 错误:丢失了y属性

避免矛盾的State

确保state之间不会出现逻辑上的矛盾,例如,一个变量表示正在发送中,另一个变量表示已发送,这两个状态不应该同时出现。

技巧:

  • 使用枚举或状态机来管理相关的状态。
  • 用一个state变量替代多个可能导致矛盾的state变量。

示例:

jsx 复制代码
const [status, setStatus] = useState('typing'); // 'typing', 'sending', 'sent'

function handleSubmit(e) {
  e.preventDefault();
  setStatus('sending');
  sendMessage(text).then(() => setStatus('sent'));
}

注意事项:

  • 避免创建逻辑上可能冲突的多个state。

正确代码:

jsx 复制代码
setStatus('sending');

错误代码:

jsx 复制代码
// 错误:定义多个状态,可能会导致状态冲突
setIsSending(true);
setIsSent(false);

避免冗余的State

不要在state中存储可以从props或其他state计算得出的值。

技巧:

  • 使用计算属性或者在渲染方法中直接计算出这些值。

示例:

jsx 复制代码
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const fullName = `${firstName} ${lastName}`;

注意事项:

  • 不要将可计算的数据存储为state。

正确代码:

jsx 复制代码
const fullName = `${firstName} ${lastName}`;

错误代码:

jsx 复制代码
const [fullName, setFullName] = useState(''); // 错误:这是一个冗余的state

避免重复的State

当相同的数据在多个地方出现时,应该考虑将其集中管理。

技巧:

  • 在state中存储唯一的标识符,而不是整个数据对象。
  • 使用查找表来管理数据。

示例:

jsx 复制代码
const [items, setItems] = useState([{ id: 1, name: 'Item 1' }]);
const [selectedId, setSelectedId] = useState(1);
const selectedItem = items.find(item => item.id === selectedId);

注意事项:

  • 避免在不同的state变量中存储相同的数据。

正确代码:

jsx 复制代码
const selectedItem = items.find(item => item.id === selectedId);

错误代码:

jsx 复制代码
const [selectedItem, setSelectedItem] = useState(items[0]); // 错误:创建了不必要的重复state

避免深度嵌套的State

深度嵌套的state很难管理和更新。尽可能地扁平化你的state结构。

技巧:

  • 使用扁平化的数据结构,如ID映射表。
  • 将复杂的state逻辑拆分到更小的组件中。

示例:

jsx 复制代码
const [plan, setPlan] = useState({
  0: { id: 0, title: 'Root', childIds: [1, 2] },
  1: { id: 1, title: 'Child 1', childIds: [] },
  2: { id: 2, title: 'Child 2', childIds: [] }
});

function handleDelete(id) {
  setPlan(prevPlan => {
    const newPlan = { ...prevPlan };
    delete newPlan[id];
    return newPlan;
  });
}

注意事项:

  • 避免在state中使用过于复杂的数据结构。

正确代码:

jsx 复制代码
const newPlan = { ...prevPlan };
delete newPlan[id];

错误代码:

jsx 复制代码
setPlan(prevPlan => {
  prevPlan[id].childIds = []; // 错误:直接修改了state
  return prevPlan;
});

记住,简化你的state结构可以减少bug,提高性能,并使你的代码更易于理解。

相关推荐
花开盛夏^.^4 小时前
电脑打开多个浏览器Web窗口占用较大的运行内存的原因
前端·浏览器
馒头不想说话5 小时前
实体店老板的24小时AI运营员工,写、剪、发全自动,省下一整个团队工资
前端
椒哥7 小时前
一天被问几十次"允许",我统计了 517 次,然后写了个插件
前端·javascript·github
风骏时光牛马7 小时前
生成一个AI稳定性治理及疑难问题分析标题,只需要一个标题,不需要其他的任何文本。
前端
莫西干式秃头7 小时前
用 AI + threejs 写了个浏览器里的 3D 动作游戏《武来》:砍怪、放技能、开 SU7
前端·人工智能·three.js
kyriewen7 小时前
我测了 6 种防请求竞态的写法:只有 1 种真能打
前端·javascript·程序员
孟健7 小时前
用 WorkBuddy 做个人名片网页,挂上开源设计技能后效果完全不同了
前端·人工智能·ai编程
IT_陈寒8 小时前
SpringBoot自动配置的坑,这次终于爬出来了
前端·人工智能·后端
LuHang9 小时前
从天地图切换到高德地图:一次真实的底图迁移实战
前端·vue.js·cesium
用户360055579009 小时前
Kestrel_VLLM - 27 · 寄存器常驻与融合发射:两次「少发一次」
前端