在React组件之间共享状态

时间:2018-08-24 19:05:14

标签: javascript reactjs

我有一个表格组件(父组件),在表格的每一行中,还有另一个组件,基本上是一个图像按钮(子组件)。单击后,图像按钮将从其默认的三个垂直点(https://png.icons8.com/windows/1600/menu-2.png)切换到下载图标。垂直的三个点图像具有一个onClick侦听器,可将其切换到下载图标,而下载图标具有一个onClick侦听器,可将其下载到表行中。每个图像按钮都有其自己的状态(基于要显示的图像)。在表格组件中,我有一个div,它包装了整个屏幕。单击该div时(基本上,如果您单击图像外部的任何位置),我希望能够将表格中的所有图像重置为三个点。我不确定如何完成此操作,因为有许多子组件,每个子组件都有自己的状态(因此,我认为redux不会起作用)。有没有一种方法可以与表格组件共享每个图像按钮的状态?

这是一些表代码

class ActionButton extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            download: false
        };
        this.toggle = this.toggle.bind(this);
    }

    toggle(e) {
        e.stopPropagation();
        this.setState({
            download: !this.state.download
        });
    }

    render() {
      return this.state.download ? (
        <div>
          <img src={Download} width='15%' onClick={(e) => this.props.downloadSong(this.props.song, e)}></img>
        </div>
      )
      : (
        <div>
          <img src={Dots} width='15%' onClick={(e) => this.toggle(e)} className='image'></img>
        </div>
      )
    }
}

这里有一些ActionButton组件

{{1}}

1 个答案:

答案 0 :(得分:2)

lift your state up在这里。实际上,首先,您不需要ActionButton组件中的状态。它应该是一个无状态组件。您可以将所有数据保留在父组件中。

我们假设歌曲数据中有一个id属性。您可以在父组件中跟踪downloadState,并将这首歌曲的id添加到此状态对象。然后,您可以将此值传递给ActionComponent并使用它。另外,您可以将所有功能保留在父组件中。

const songs = [
  { id: "1", name: "Always Blue", artist: "Chet Baker", duration: "07:33" },
  { id: "2", name: "Feeling Good", artist: "Nina Simone", duration: "02:58" },
  { id: "3", name: "So What", artist: "Miles Davis", duration: "09:23" },
]

class App extends React.Component {
  state = {
    downloadState: {},
  }
  
  toggle = ( e, id ) => {
    e.stopPropagation();
    this.setState( prevState => ({
      downloadState: { ...prevState.downloadState, [id]: !prevState.downloadState[id]}
    }))
  }

  downloadSong = ( e, song ) => {
    e.stopPropagation();
    alert( song.name );
  }

  resetDownloads = () => this.setState({ downloadState: {}});
  

  render() {
    return (
      <div onClick={this.resetDownloads}>
      <table>
        <tbody>
        {
          songs.map((song, index) => (
          <tr key={index}>
            <td>{song.name}</td>
            <td>{song.artist}</td>
            <td>{song.duration}</td>
            <td>
            <ActionButton
              toggle={this.toggle}
              song={song}
              downloadState={this.state.downloadState}
              downloadSong={this.downloadSong}
            />
            </td>
          </tr>
          ))
        }
        </tbody>
      </table>
      </div>
    )
  }
}

const ActionButton = props => {
  const { downloadState, downloadSong, song, toggle } = props;
  
  const handleToggle = e => toggle(e, song.id);
  const handleDownload = e => downloadSong( e, song );
  
  const renderImages = () => {
    let images = "";
    if ( downloadState[song.id] ) {
      images = <p onClick={handleDownload}>Download</p>;
    } else {
      images = <p onClick={handleToggle}>Dots</p>;
    }
    return images;
  }

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

ReactDOM.render(<App />, document.getElementById("root"));
table, th, td {
    border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

如果没有任何id属性,则可以使用索引设置相同的逻辑,但是我认为每个数据都应该有一个id :)也许可以使用相同的逻辑来代替索引带有歌曲名称,因为它们几乎是唯一的。谁知道:)