繁体   English   中英

如何使父/包装组件“触发”或在子组件上调用方法?

[英]How to make a parent/wrapper component “trigger” or call methods on children?

假设我有以下几点:

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

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

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

我不知道的是,如何在不使用Redux之类的情况下使Group触发Item的方法? (我正在尝试使这些组件尽可能简单和纯净)

您不能也不应。 但是在少数情况下,可能需要设置焦点或触发不会真正改变状态的操作。 此问题的关键是尚未创建DOM。 react doc中有一个示例。

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

因此,在这里设置ref属性,然后在安装dom后设置焦点。 在其他情况下,我建议使用从父组件到子组件的传递属性来做所有事情。

更多帮助的事情:

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

我的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() (就像用户单击了播放按钮一样)。 奇迹般有效。

我在这里假设您正在尝试播放下一首歌? 我可能尝试解决此问题的方法是通过传递另一个道具(可能是布尔值)来确定歌曲是否在渲染器上播放。 父母将跟踪在其状态内上一曲,正在播放或下一曲播放。 当您的歌曲结尾事件触发时,父级将调用setState并更新每个状态值,并相应地重新渲染其自身及其子级。

组件):

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('...')
);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM