【问题标题】:How to make a parent/wrapper component "trigger" or call methods on children?如何使父/包装器组件“触发”或调用子组件的方法?
【发布时间】:2016-08-05 11:36:06
【问题描述】:

假设我有以下内容:

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

我想不通的是,如何让GroupItem 中触发一个方法,而不使用 Redux 之类的东西? (我试图让这些组件尽可能简单和纯粹)

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

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

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

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

    更多帮助:

    【讨论】:

      【解决方案2】:

      想出了一个不涉及 hack 或 refs 的解决方案,并认为我会分享。

      我的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()(就像用户单击了播放按钮一样)。像魅力一样工作。

      【讨论】:

        【解决方案3】:

        我在这里假设您正在尝试播放下一首歌曲?我可能尝试解决这个问题的方法是传递另一个道具,可能是一个布尔值,它确定歌曲是否在渲染时播放。父级将跟踪在其状态内最后播放、正在播放或将要播放的歌曲。当您的歌曲结束事件触发时,父级将调用 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('...')
        );
        

        【讨论】:

          猜你喜欢
          • 2018-07-16
          • 2018-10-27
          • 2021-05-02
          • 1970-01-01
          • 2018-06-08
          • 2016-12-08
          • 2020-06-15
          相关资源
          最近更新 更多