用State响应输入
用State响应输入
声明式地考虑UI
流程
- 定位你的组件中不同的视图状态
- 确定是什么触发了这些 state 的改变
- 表示内存中的 state(需要使用
useState) - 删除任何不必要的 state 变量
- 连接事件处理函数去设置 state
步骤一:定位组件中不同的视图状态
首先,你需要去可视化 UI 界面中用户可能看到的所有不同的“状态”:
- 无数据:表单有一个不可用状态的“提交”按钮。
- 输入中:表单有一个可用状态的“提交”按钮。
- 提交中:表单完全处于不可用状态,加载动画出现。
- 成功时:显示“成功”的消息而非表单。
- 错误时:与输入状态类似,但会多错误的消息。
像一个设计师一样,你会想要在你添加逻辑之前去“模拟”不同的状态或创建“模拟状态”。
如果一个组件有多个视图状态,你可以很方便地将它们展示在一个页面中:类似这样的页面通常被称作“living styleguide”或“storybook”。
步骤二:确定是什么触发了这些状态的改变
你可以触发 state 的更新来响应两种输入:
- 人为输入。比如点击按钮、在表单中输入内容,或导航到链接。
- 计算机输入。比如网络请求得到反馈、定时器被触发,或加载一张图片。
以上两种情况中,你必须设置 state 变量 去更新 UI。对于正在开发中的表单来说,你需要改变 state 以响应几个不同的输入:
- 改变输入框中的文本时(人为)应该根据输入框的内容是否是空值,从而决定将表单的状态从空值状态切换到输入中或切换回原状态。
- 点击提交按钮时(人为)应该将表单的状态切换到提交中的状态。
- 网络请求成功后(计算机)应该将表单的状态切换到成功的状态。
- 网络请求失败后(计算机)应该将表单的状态切换到失败的状态,与此同时,显示错误信息。
为了可视化这个流程,请尝试在纸上画出圆形标签以表示每个状态,两个状态之间的改变用箭头表示。你可以像这样画出很多流程并且在写代码前解决许多 bug。
步骤3:通过useState表示内存中的state
诀窍很简单:state 的每个部分都是“处于变化中的”,并且你需要让“变化的部分”尽可能的少。更复杂的程序会产生更多 bug!
先从绝对必须存在的状态开始
如果你很难立即想出最好的办法,那就先从添加足够多的 state 开始,确保所有可能的视图状态都囊括其中
你最初的想法或许不是最好的,但是没关系,重构 state 也是步骤中的一部分!
步骤4:删除任何不必要的state变量
防止出现在内存中的 state 不代表任何你希望用户看到的有效 UI 的情况
这有一些你可以问自己的, 关于 state 变量的问题:
- 这个 state 是否会导致矛盾?例如,
isTyping与isSubmitting的状态不能同时为true。矛盾的产生通常说明了这个 state 没有足够的约束条件。两个布尔值有四种可能的组合,但是只有三种对应有效的状态。为了将“不可能”的状态移除,你可以将'typing'、'submitting'以及'success'这三个中的其中一个与status结合。 - 相同的信息是否已经在另一个 state 变量中存在?另一个矛盾:
isEmpty和isTyping不能同时为true。通过使它们成为独立的 state 变量,可能会导致它们不同步并导致 bug。幸运的是,你可以移除isEmpty转而用message.length === 0。 - 你是否可以通过另一个 state 变量的相反值得到相同的信息?
isError是多余的,因为你可以检查error !== null。