如何制作父/包装组件"触发"还是给孩子打电话的方法?

时间:2016-04-14 05:02:43

标签: javascript reactjs

我们说我有以下内容:

<Group>
  <Item mediaUrl="http://some/media/file.mp3" />
  <Item mediaUrl="http://another/media/file.mp3" />
</Group>

当第一个文件播放完毕后,我可以通过通过道具传递的方法通知Group

// Group.js
const items = React.Children.map(this.props.children, (child, i) => {
  // ...
  return React.cloneElement(child, { onEnd: this.handleEnd });
});

我无法弄清楚的是,如何在GroupItem触发方法,而不使用像Redux这样的东西? (我试图保持这些组件尽可能简单和纯粹)

3 个答案:

答案 0 :(得分:2)

你不能也不应该。但在极少数情况下,如设置焦点或触发一些并未真正改变状态的东西,可能需要它。这个问题的关键是还没有创建DOM。 react doc中有一个例子。

render: function() {
  return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
  this._input.focus();
},

所以在这里设置ref属性,然后在安装dom之后设置焦点。在其他情况下,我建议使用从父组件到子组件的属性传递来完成所有操作。

更多可以提供帮助:

答案 1 :(得分:0)

找出一个不涉及黑客或参考的解决方案,并且认为我会分享。

我的Group组件有以下方法:

  componentDidMount() {
    this.setState({
      playlist: React.Children.map(this.props.children, t => t.props.id),
    });
  }

  render() {
    if (!this.props.children) {
      console.error('Warning: TrackGroup must contain audio tracks');
      return null;
    }

    const tracks = React.Children.map(this.props.children, (child, i) => {
      return React.cloneElement(child, {
        onTrackEnd: this.trackEnded,
        playNext: this.state.playNext,
      });
    });

    return <div>{tracks}</div>
  }

当每个Item(跟踪)componentWillReceiveProps触发时,我会检查nextProps.playNext以查看它是否与this.props.id匹配。如果是,则音频呼叫this.clickedPlay()(就像用户点击了播放按钮一样)。像魅力一样。

答案 2 :(得分:0)

我在这里假设您正在尝试播放下一首歌?我试图解决这个问题的方法是传递另一个道具,可能是一个布尔值,它决定了歌曲是否在渲染时播放。家长将跟踪哪个歌曲最后播放,正在播放或将在其状态下播放。当您的歌曲结束事件触发时,父级将调用setState并更新每个状态值并相应地重新呈现自身及其子级。

成分(S):

class Group extends React.Component {
  constructor(props) {
    super(props)
  }
  state = {
    // Initial state. Be careful pressing the back button on the first song :p (Obviously improve this)
    previous: -1,
    current: 0,
    next: 1
  }
  handleEnd = () => {
    // Perform all sorts of condition checks for first song, last song, etc. and code accordingly. This is simplistic, proceeding in linear fashion. You can extrapolate this into other methods for selection of any song, back or forward button, etc.
    if (...) {
      this.setstate({
        previous: previous += 1,
        current: current += 1,
        next: next +=1
      });
    }
  }
  render () {
    let songs = this.props.songs;

    let songList = songs.map((song) => {
      if (song.index === this.state.current) {
        return (
          <Item playing=1 onEnd={this.handleEnd} mediaUrl={song.url} />
        );
      }
      else {
        return (
          <Item playing=0 onEnd={this.handleEnd} mediaUrl={song.url} />
        );
      };
    }

    return (
      <div>
        {songList}
      </div>
    );
  }
}

class Item extends React.Component {
  constructor(props) {
    super(props)
  }
  componentDidMount = () => {
    if (this.props.playing === 1) {
      this.play();
    };
  }
  play = () => {
    // Play the music from the url or whatever.
  }
  render () {
    <div>
      // Some graphical representation of song.
    </div>
  }
}

创建新的播放列表组件:

someSongs = [...];
ReactDOM.render(
  <Group songs={someSongs} />,
  document.getElementById('...')
);