React:告诉子组件“重新初始化”,即使传递的道具相同
Posted
技术标签:
【中文标题】React:告诉子组件“重新初始化”,即使传递的道具相同【英文标题】:React: Tell child component to "reinitialize," even when the passed props are the same 【发布时间】:2021-04-28 23:56:12 【问题描述】:我有一个呈现 Timer 组件的 MyComponent。我目前的设置是这样的:
MyComponent.render:
render ()
return <Timer time=this.state.time lag=this.lag || 0 />
计时器:
class Timer extends Component
constructor(props)
super(props);
this.state =
time: this.props.time,
;
startTimer = (duration) =>
if (duration > 0)
this.on = true;
let timer = duration * 1000 + this.props.lag;
var s = setInterval(() =>
this.setState(time: Math.round(timer/1000));
timer = timer - 500;
if (timer <= 0)
this.on = false;
clearInterval(s);
, 500);
componentDidMount = () =>
this.startTimer(this.props.time);
render()
return (
<div className="Timer-container">
<div className="Timer-value">this.state.time</div>
</div>
);
如您所见,当 Timer 初始化时,它立即开始倒计时。在MyComponent
的后续渲染中,我想重新启动Timer
,即使time
道具没有改变。换句话说,我希望它在每次渲染时“重新初始化”。我如何做到这一点?
【问题讨论】:
你试过从render()
中调用函数吗?
@Justinas 我不确定你的意思;你能详细说明一下吗?
内部渲染:clearInterval(this.s); this.startTimer(1000)
不要以为你想放入render()
,因为它会在每次本地状态变化时调用该函数,我认为你可以调用componentWillReceiveProps
中的函数,它会跳过本地状态,但只听父母重新渲染
作为一种解决方法,您可以将time
包装到一个对象中,每次您想重新启动计时器时,您都会传递一个新对象,即使在同一时间time=value:500
并且在组件中读取的是作为props.time.value
。您可能需要重构代码,以便停止旧计时器(当然,如果您想停止它)
【参考方案1】:
-
首先,要重置计数器,需要在状态中存储一些东西,
-
如果您想在父级重新渲染(但道具没有改变)时做某事,基本上您需要检查的是为什么您的组件更新了。答案是"Trace why a React component is re-rendering"
您的示例的一种快速方法是检查状态是否已更改(不推荐):
componentDidUpdate(prevProps, prevState, snapshot)
if( prevState === this.state )
clearInterval( this.state.interval );
this.startTimer( this.props.time );
另一个快速解决方案是(如果您可以选择)将shouldRerender
属性传递给组件,然后在组件内检查此属性:
// -- inside MyComponent
render ()
return <Timer
time= this.state.time
lag= this.lag || 0
shouldRerender= /* just an empty object */ />;
// -- inside Timer
componentDidUpdate(prevProps, prevState, snapshot)
if( prevProps.shouldRerender !== this.props.shouldRerender )
clearInterval( this.state.interval );
this.startTimer( this.props.time );
对我来说这看起来有点“脏”。一种更简洁的方法是将一些状态传递给shouldRerender
,它会随着每次更新而改变(例如,只是增加数字)。
但是,我认为检查父级是否呈现的方法是不是 React 方式。我个人确实会考虑组件是否渲染一个实现细节(我不知道这样说是否正确),也就是说,我不在乎 React 何时决定渲染,我只关心道具和状态(基本上)。
我建议您考虑一下“因果”究竟是什么,您想要重置计时器的原因是什么。父母的重新渲染可能只是其他原因的影响,您也可以将其用于时间重置。
这里有一些不同的概念可能对我可以想象的用例有用:
不使用一个 Time 实例,而是在需要时在父级内部销毁和创建,也可以使用key
道具。
使用HOC(如withTimer
)或custom hook(如useTimer
),注入reset()
函数(另外创建一个单独的TimerView
组件)
保持time
状态在MyComponent
,将time
和onChange
向下传递到Timer
组件(<Timer time= this.state.time onChange= time => this.setState( time: time ); />
),然后MyComponent
和Timer
都可以设置/重置时间.
【讨论】:
以上是关于React:告诉子组件“重新初始化”,即使传递的道具相同的主要内容,如果未能解决你的问题,请参考以下文章