从父级到子级发起事件

时间:2018-10-19 11:51:43

标签: reactjs

有下一种情况-有隔离组件Timer: enter image description here 从指定时间到哪一个滴答时间都为0。超过计时器的时间将启动回调函数。我对上面的实施情况没有问题,但是还有另一种情况。我需要通过父组件的某个事件来重新启动计时器-它可以是所有内容(用户单击等)。太...我该如何从父组件启动此事件?

在相同的情况下,我对子组件使用了ref,并通过ref统治了子组件和Child状态。但是我认为这是不好的做法。如此...也许有人还有另外一句话?

代码示例:https://codesandbox.io/s/52r3149rzn

2 个答案:

答案 0 :(得分:2)

您想要的是修改子组件的状态。这不是反应的原理。 React是一种方法-从上到下。

如果需要在某些组件之间共享某些数据,请将该数据移动到树中最近的公共父级。如果在反应树的许多不同节点中需要状态,最明显的是,当存在仅传递信息的中间组件时,请使用上下文或专用状态容器,例如redux。

这是使用上下文的计时器实现:

Timer为所有子代后代提供时间信息和功能。

可以使用Time组件获取当前时间,并可以使用ResetTime重置功能。<​​/ p>

此解决方案非常容易组合。通过这两个简单的组件,您可以在应用程序中的任何位置使用计时器功能。

import Timer, { Time, ResetTime } from "./Timer";

function App() {
  return (
    <Timer>
      <div className="App">
        <Time>{time => <p>{time}</p>}</Time>
        <ResetTime>{reset => <button onClick={reset}>reset</button>}</ResetTime>
      </div>
    </Timer>
  );
}

import React from "react";

const TimerContext = React.createContext();

export default class Timer extends React.Component {
  reset = () => {
    this.stop();
    this.start();
  };
  stop = () => {
    clearInterval(this.interval);
  }
  start = () => {
    this.setState(({time}) => ({time: 15}))
    this.interval = setInterval(() => {
      this.setState(({ time }) => {
        if (time > 0) {
          return { time: time - 1 };
        } else {
          this.stop();
        }
      });
    }, 1000);
  };
  state = {
    time: 15,
    reset: this.reset
  };
  componentDidMount() {
    this.start();
  }
  componentWillUnmount() {
   this.stop();
  }
  render() {
    return (
      <TimerContext.Provider value={this.state}>
        {this.props.children}
      </TimerContext.Provider>
    );
  }
}

export const TimerConsumer = TimerContext.Consumer;

export const Time = ({children}) => <TimerConsumer>
  {({time}) => children(time)}
</TimerConsumer>

export const ResetTime = ({children}) => <TimerConsumer>
{({reset}) => children(reset)}
</TimerConsumer>

答案 1 :(得分:1)

在React中,您可以通过两种不同的方式让父级交流孩子。

  1. 设置道具。这调用了一组生命周期,最后调用了Child.render()
  2. ref +调用某些方法。这个Child的方法可以做任何事情,一旦调用了this.setState组件,它将被重新渲染。

在您的情况下,使用道具重置计时器会很麻烦。它应该是布尔型(reset={true})还是字符串(current-time={'00:00'})还是数字?当我们重置计时器而不是正在运行的计时器并再次重置时,如何跟踪情况(将该道具设置为与reset={true}完全相同的值没有意义)?我们需要在componentDidUpdate中进行大量检查,以确保在重置计时器和不重置计时器时,情况有所不同。

另一方面,呼叫timerRef.reset()看起来非常清晰直接。

不,使用ref本身并不是一个坏习惯。 Uncontrolled components are