Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript react中组件之间通信的正确方式是什么?为什么不到处使用ref?_Javascript_Reactjs_Components_Ref - Fatal编程技术网

Javascript react中组件之间通信的正确方式是什么?为什么不到处使用ref?

Javascript react中组件之间通信的正确方式是什么?为什么不到处使用ref?,javascript,reactjs,components,ref,Javascript,Reactjs,Components,Ref,我知道这个问题被问了很多次,但到目前为止我找不到一个合理的答案 如果我想制作一个应用程序,它有两个组件:按钮和显示时间的计时器。单击按钮后,计时器将启动/暂停/重置。对于我来说,作为React的初学者,最明显的方法是在计时器中创建start()pause()reset()方法,然后单击按钮调用此函数(使用refs) 但是根据React doc和所有教程,这应该避免。应该是start()pause()reset()方法保存在最顶层的组件中(“按钮”和“计时器”组件的父级),从那里它们应该控制计时器

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

如果我想制作一个应用程序,它有两个组件:按钮和显示时间的计时器。单击按钮后,计时器将启动/暂停/重置。对于我来说,作为React的初学者,最明显的方法是在计时器中创建start()pause()reset()方法,然后单击按钮调用此函数(使用refs)

但是根据React doc和所有教程,这应该避免。应该是start()pause()reset()方法保存在最顶层的组件中(“按钮”和“计时器”组件的父级),从那里它们应该控制计时器

但万一我想要10个不同的计时器(相同的组件不同的设计),该怎么办?如果在计时器中定义了启动、暂停和重置方法,那么顶层组件就没有30种方法了,这难道不是干法编码吗


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

给出您的示例,说明将实现“向上”的意义在这些层上,您可以在应用程序的不同部分使用相同的计时器组件,其中start()每次的行为可能会有所不同。 组件本身无法知道每个特定的“启动”事件应该做什么,因为组件在任何时候都不应该知道如何使用它

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

这实际上会强制执行DRY,因为您需要一个计时器(启动、暂停、停止的逻辑、“计时器到达”可能等等),然后每个调用方连接在这些事件发生时他想要做的事情

如果你想一想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();
    }
当然,现在呼叫者将不负责实现实际的滴答声(尽管有一天有人可能会来请求一个与光速或其他速度相关的跟踪器,因此滴答声也可以配置…),但是如果他们确实需要在开始事件上设置一个钩子,他们会,然后你可以用这种方式实现它。 组件不知道回调函数的作用(业务逻辑向上移动),但是调用方现在不关心所有“每秒勾选一次”的共同点

编辑3: 好吧,那么。。如果单击按钮,我们将启动计时器,然后调用道具提供的任何挂钩

 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)}>

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


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

“重点是能够在应用程序的不同部分使用相同的计时器组件”-当我想要两个计时器时,我需要在顶层修改分别计算每个计时器时间的功能。但是如果计时功能在计时器内,那么我可以通过复制再次使用计时器。如果我把所有的逻辑都放在上面,那么用来显示时间的计时器组件复制它是完全无用的,因为它的逻辑在应用程序的主组件中。哦,天哪,你需要把“逻辑”部分和“特定业务”部分分开。这意味着“计算时间”函数应该在组件中,因为它不会改变!对于我们来说,时间总是以同样的速度流逝,所以没有必要向上移动这部分组件。但是您应该有一个OnStart,例如,调用者将能够钩住他们自己的方法,“但是您需要公开OnStart、OnStop、OnPause”->谢谢,所以唯一的问题是如何做到这一点?REF允许您访问这些方法。或者按照salomari87回答中的建议,将道具传递给计时器,然后在计时器中等待该道具更改?好的,thx,但问题是计时器如何知道开始计时?如何在计时器内部触发这个滴答声?好的,现在我看到了“你的问题”,问题是计时器组件与按钮平行,所以你的this.start()必须告诉计时器组件运行它的start()方法并开始滴答声。在我看来,按钮和计时器都是子组件。您必须使用ref,对吗?是的,这听起来很合理:我将click事件传递给timer。所以我创建了一个属性值,比如布尔值,在componentDidUpdate()内的计时器中,我检查这个布尔值是否已更改(为true或false,无关紧要-更改很重要)。谢谢,这很有道理。但是这种编码方式看起来比使用refs复杂得多,而且它不是很直观,我的意思是React可能