javascript - React useRef 或模块范围以存储与 UI 无关的状态
问题描述
假设currentSelected
在 React 功能组件中调用了一个独立于 UI 的状态。它存储当前选择的项目,并将在某个时间使用。
有两种方法可以将状态useRef hook
或模块范围存储在组件之外。
useRef 钩子:
function Example() {
const currentSelected = useRef()
useEffect(() => {
// access currentSelected state
})
function handleClick(item) {
currentSelected.current = item
}
return (
<ul>
{items.map(item => <li onClick={() => handleClick(item)}>item.name</li>)}
</ul>
)
}
模块范围:
let currentSelected = null
function Example() {
useEffect(() => {
// access currentSelected state
})
function handleClick(item) {
currentSelected = item
}
return (
<ul>
{items.map(item => <li onClick={() => handleClick(item)}>item.name</li>)}
</ul>
)
}
哪种方法更适合存储与 UI 无关的状态currentSelected
?
以及存储状态的应用场景useRef
和模块范围是什么?
========= 更新===========
UI 独立意味着您不想在更新状态后触发重新渲染。相比之下,UI 相关的状态就是这样做的。
解决方案
useRef
和模块范围变量之间的区别
为了完整起见,我也会加入useState
。
useState
:与组件实例相关联的不可变数据,并通过setter函数在更改时触发渲染。useRef
:与组件实例相关联的可变数据,但不会在更改时触发任何渲染。- 模块范围变量:与模块相关联的可变数据,由于它完全在 React 之外,因此也不会在更改时触发任何渲染。
用例useRef
如果您不止一次地安装一个组件,例如在两个页面上使用它,useRef
将确保每个组件实例都有自己的可变值。
// Here, the Example component could be used in multiple places
// and each instance would successfully keep its own state while
// not triggering renders on changes.
function Example() {
const currentSelected = useRef()
useEffect(() => { /* access currentSelected state */ })
return (
<ul>
{items.map(item => (
<li onClick={() => { currentSelected.current = item }}>{item.name}</li>
))}
</ul>
)
}
模块范围变量的用例
如果您正在寻找类似单例的模式或类似静态的变量,例如对于某种应用程序范围的共享数据,那么模块范围变量将使这成为可能,就像在任何 vanilla JS 模块中一样。
// Here, the count value will be initialized once and then shared between every
// instances across the app, ever.
let count = 0;
function Example() {
// Won't trigger a render, so some Example instance could still show the old value.
count += 1;
return <span>Combined renders of all the Example components: {count}</span>;
}
请注意,它不会在count
更改时触发渲染,因此您不应该那样使用它。
注意事项
如果在组件也只挂载一次的地方只使用一次,这两种模式的行为似乎相似,但最终,触发重新挂载只是时间问题,然后您将面临一个奇怪的错误。
在对包含模块范围变量的模块进行单元测试时,您也可能会遇到问题,因为它可能无法在测试用例之间正确重置。一个快速的解决方法是只导出变量并让测试用例更改其值,但请注意不要在其他任何地方更改它。尽管这应该根据具体情况进行评估。
推荐阅读
- javascript - 未找到模块:错误:无法解析...使用外部 JS 库时
- python - 从串口读取数据有问题
- android - Android 信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR),故障地址 00000023
- elasticsearch - ElasticSearch 嵌套必须和应该
- python - Boost Python - 用参数包装构造函数
- c# - 使用 Selenium 和 React 等待渲染事件
- azure - 每次触发警报时,连接到逻辑应用 Webhook 的 Azure 警报操作都会触发两次
- javascript - 为什么我的 Vue 组件在 javascript ajax catch 块中为空?
- javascript - 当用户键入时,NgOnChanges 会覆盖表单控件的值
- javascript - 使用请求登录回环 API 失败