反应中组件之间通信的正确方式是什么?为什么不到处使用 refs 呢?

What is the proper way of communicating between components in react? Why not using refs everywhere?

我知道这个问题被问过很多次,但到目前为止我找不到一个合理的答案。

如果我想制作一个应用程序,它有两个组件:按钮和显示时间的计时器。单击按钮时,计时器 starts/pauses/resets。作为 React 的初学者,最明显的方法是在计时器内创建 start() pause() reset() 方法,然后单击按钮调用此函数(使用 refs)。

但是根据 React 文档和所有教程,应该避免这种情况。应该是 start() pause() reset() 方法保留在最顶层组件("buttons" 和 "timer" 组件的父级),并且从那里他们应该控制计时器。

但是如果我想要 10 个不同的计时器(相同的组件不同的设计)怎么办?在计时器内部定义启动、暂停、重置方法难道不是 DRY 编码,所以顶级组件没有 30 个方法吗?

这是一个 hipotetical 示例,请不要给我解决方法,我想了解将所有逻辑都放在顶级组件中的原因,使子组件不可作为独立组件重用。

鉴于您的示例,在层上移动实现 "up" 的要点是能够在应用程序的不同部分使用相同的计时器组件,其中 start() 每次的行为可能都不同. 组件本身无法知道每个特定的 "start" 事件应该做什么,因为组件在任何时候都不应该知道它是如何被使用的。

将回调视为事件处理程序,调用者在其中传递事件发生时应执行的操作

这实际上强制执行 DRY,因为您需要 1 个计时器(开始、暂停、停止的逻辑,"timer reached" 可能等等),然后每个调用者在这些事件发生时连接他想做的事情。

如果你想到React本身的结构,和它的生命周期事件,其实是一回事。例如,"ComponentDidMount" 与计时器的 "start" 没有什么不同,只是上下文不同。概念思路一样

编辑:重要的是要考虑什么在你的组件中对每个人来说都是固定的,什么应该是可配置的。 例如,您的计时器将始终每秒滴答一次,对吗?因此,时间跟踪部分对于您的应用程序将始终保持不变,它应该驻留在组件中。该组件应该在其中定义一组 Start、Pause、Stop 方法,因为 stop 将始终只是停止计数,而 start 将始终恢复它。 但是您需要公开一个 OnStart、OnStop、OnPause,以便调用者可以使用您的计时器挂接他们需要的逻辑。我不知道我是否能解释得足够好...

编辑 2: 例如,检查下面的计时器启动方法:

 function Start(){
    // set the interval here or wtver way you will have to measure ticks
// ...
// ...
    if(this.props.OnStart)
     this.props.OnStart();
    }

现在调用者当然不会负责实现实际的滴答声(尽管有一天有人可能会来请求一个与某人以光速或其他速度旅行相关的跟踪器,因此滴答声也可以是可配置的。 ..), 但如果他们确实需要在开始事件上有一个钩子,并且他们会这样做,那么您可以通过这种方式实现它。 组件不知道回调函数的作用(业务逻辑向上移动),但是调用者 'tick once per second' 现在不关心通用的

编辑 3: 好吧..如果点击按钮,我们将启动计时器,然后调用 props

给出的任何钩子
 function OnEveryClick(){
    // here you will write anything you want your component to do every time the button is clicked, regardless of who is the caller, like our previous Start method
this.Start();
    }

function ButtonClicked(){
// first you call your method every time
 this.OnEveryClick();
// then if the caller also wants to do some stuff, you evaluate their function aswell
  if(this.props.OnSubmit)
    this.props.OnSubmit();
}

然后在渲染器上做这样的事情

<button onClick={this.ButtonClicked.bind(this)}>

在我看来,你不必在任何顶级组件中都有定时器方法,定时器必须只知道按钮已被点击,在这种情况下你通过道具将点击事件传递给定时器,即假设计时器和按钮在同一个函数中呈现。这意味着也没有裁判。当计时器组件收到新的道具时,它将重新渲染。

同样适用于计时器组件内的多个计时器。