随着你的应用不断变大,更有意识的去关注应用状态如何组织,以及数据如何在组件之间流动会对你很有帮助。冗余或重复的状态往往是缺陷的根源。
使用状态响应输入
使用 React,你不用直接从代码层面修改 UI。例如,不用编写诸如“禁用按钮”、“启用按钮”、“显示成功消息”等命令。相反,你只需要描述组件在不同状态(“初始状态”、“输入状态”、“成功状态”)下希望展现的 UI,然后根据用户输入触发状态更改。这和设计师对 UI 的理解很相似。
选择状态结构
良好的状态组织,可以区分开易于修改和调试的组件与频繁出问题的组件。最重要的原则是,状态不应包含冗余或重复的信息。如果包含一些多余的状态,我们会很容易忘记去更新它,从而导致问题产生!
在组件间共享状态
有时候你希望两个组件的状态始终同步更改。要实现这一点,可以将相关状态从这两个组件上移除,并把这些状态移到最近的父级组件,然后通过 props 将状态传递给这两个组件。这被称为“状态提升”。
保留和重置状态
当你重新渲染一个组件时, React 需要决定组件树中的哪些部分要保留和更新,以及丢弃或重新创建。在大多数情况下, React 的自动处理机制已经做得足够好了。默认情况下,React 会保留树中与先前渲染的组件树“匹配”的部分。
React 允许你覆盖默认行为,可通过向组件传递一个唯一 key
(如 <Chat key={email}/>
来 强制 重置其状态。这会告诉 React ,如果收件人不同,应将其作为一个 不同的 Chat
组件,需要使用新数据和 UI(比如输入框)来重新创建它。现在,在接收者之间切换时就会重置输入框——即使渲染的是同一个组件。
<Chat key={to.email} contact={to} />
提取状态逻辑到 reducer 中
对于那些需要更新多个状态的组件来说,过于分散的事件处理程序可能会令人不知所措。对于这种情况,你可以在组件外部将所有状态更新逻辑合并到一个称为 “reducer” 的函数中。这样,事件处理程序就会变得简洁,因为它们只需要指定用户的 “actions”。在文件的底部,reducer 函数指定状态应该如何更新以响应每个 action!
const [tasks, dispatch] = useReducer(
tasksReducer,
initialTasks
);
dispatch({
type: 'added',
id: nextId++,
text: text,
});
function tasksReducer(tasks, action) {
switch (action.type) {
case 'added': {
...
使用 Context 进行深层数据传递
Context 允许父组件将一些信息提供给它下层的任何组件,不管该组件多深层也无需通过 props 逐层透传。
使用 Reducer 和 Context 进行状态扩展
Reducer 帮助你合并组件的状态更新逻辑。Context 帮助你将信息深入传递给其他组件。你可以将 reducers 和 context 组合在一起使用,以管理复杂应用的状态。
基于这种想法,使用 reducer 来管理一个具有复杂状态的父组件。组件树中任何深度的其他组件都可以通过 context 读取其状态。还可以 dispatch 一些 action 来更新状态。