如何在使用 useState 钩子的功能组件的不同实例之间隔离状态?



示例是使用useState来保持点击计数器的简单功能组件。

逐步完成步进 MUI 组件,我想创建具有不同初始化值的示例组件实例,例如在步骤 0、初始化值 100、步骤 1、初始化值 111、在步骤 2、初始化值 112。

在逐步执行步骤的每个情况时,尽管传递了不同的初始值,但示例功能组件仅将状态保留为第一个初始化值,即 100。

文件是/Components/Navigation/Stepper01a.js,示例组件在 StepContent 中引用,该组件在 HorizontalLinearStepper 组件中引用。整体代码是材质 UI 步进器组件的示例。我只是尝试测试它以创建其他功能组件的不同实例(在这种情况下的示例),每一步都有不同的初始值。

示例组件:

function Example({ init }) {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = React.useState(init)
return (
<div>
<p>init {init} </p>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
)
}

步骤内容组件:

function StepContent({ step }) {
console.log("step", step)
switch (step) {
case 0:
return <Example init={100} />
case 1:
return <Example init={111} />
case 2:
return <Example init={112} />
default:
return "Unknown step"
}
}

水平线性步进器组件:

export default function HorizontalLinearStepper() {
...
<div>
<StepContent step={activeStep} />
</div>
...
}

请参阅运行示例 https://mj3x4pj49j.codesandbox.io/代码 https://codesandbox.io/s/mj3x4pj49j

在步骤 0 中单击"下一步"后,计数应设置为初始化值为 111,但仍为 100,在步骤 1 单击"下一步"时,计数应设置为 init 值 112,但再次保持为 100。似乎一旦在步骤 0 将状态计数初始化为 100,就会在步骤 1 和 2 中使用相同的状态,即状态不是隔离的。

此问题是否由于以某种方式违反了钩子规则而发生?

在组件内部,您正在正确执行。从props获取的初始化值 - 这是常见的做法。

但是看,useState()只在初始渲染上应用 init 值(componentDidMountconstructor对于基于类的组件)。使用该组件的方式没有重新创建<Example而是更新它。

换句话说,同样的情况是,你会得到基于类的组件而没有componentDidUpdate:React 更新现有<Example>而不是重新创建它,并且不再componentDidMount应用(对于你的情况,它不会以初始值初始化useState)。

我看到了不同的处理方式。

  1. 强制 React 重新创建元素,而不是使用key进行更新。笨拙但工作方式:
switch (step) {
case 0:
return <Example key="step-1" init={100} />
case 1:
return <Example key="step-2" init={111} />
case 2:
return <Example key="step-3" init={112} />
default:
return "Unknown step"
}
  1. 您可以使用useEffect作为componentDidUpdate的钩子版本:
useEffect(() => {
setCount(init);
}, [init]);

这是一个棘手的时刻,因为您正在计算点击次数。因此,只做setCount(init)可能不是好举动,并且会破坏您的计算。所以实际代码可能要复杂得多。我在这里不确定,因为不明白计数背后的逻辑。

  1. 提升状态向上(count推送到父组件)时,更新init后无需更新任何内容。

你需要给 React 一个提示,在不同的步骤中你需要不同的示例组件实例。这个提示可以这样完成:

function StepContent({ step }) {
console.log("step", step)
switch (step) {
case 0:
return <Example init={100} key={0} />
case 1:
return <Example init={111} key={1} />
case 2:
return <Example init={112} key={2}/>
default:
return "Unknown step"
}
}

原因是 React 在所有情况下都在虚拟 dom 中看到一个示例,并且根据其算法,它认为它是相同的组件但具有不同的道具,因此他只是更改其状态而不重新初始化它。

最新更新