javascript - 在 React 组件之间共享状态
问题描述
我有一个表格组件(父级),并且在表格的每一行中,还有另一个组件基本上是一个图像按钮(子级)。单击时,图像按钮会从其默认的三个垂直点(https://png.icons8.com/windows/1600/menu-2.png) 到下载图标。三个垂直点图像有一个 onClick 监听器,将其切换到下载图标,下载图标有一个 onClick 监听器,用于下载表格行中的文件。每个图像按钮都有自己的状态(基于要显示的图像)。在表格组件中,我有一个包裹整个屏幕的 div。单击该 div 时(基本上,如果您单击图像之外的任何位置),我希望能够将表中的所有图像重置回三个点。我不确定如何做到这一点,因为有很多子组件,每个子组件都有自己的状态(因此我认为 redux 不会工作)。有没有办法与表格组件共享每个图像按钮的状态?
这是一些表格代码
<div className='shield' onClick={() => this.resetDownloads()}></div>
<table className='table table-striped'>
<tbody>
this.props.songs.data.map((song, index) =>
<tr key={index}>
<td>{song.name}</td>
<td>{song.artist}</td>
<td>{song.duration}</td>
<td><ActionButton song={song}/></td>
</tr>
</tbody>
</table>
这是一些 ActionButton 组件
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
实际上,首先,您的组件中不需要状态。它应该是一个无状态组件。您可以将所有数据保存在父组件中。
假设id
歌曲数据中有一个属性。您可以在父组件中跟踪 adownloadState
并将这首歌添加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
:) 也许可以将相同的逻辑用于歌曲名称而不是使用索引,因为它们几乎是唯一的。谁知道 :)
推荐阅读
- python - 从 python 运行 docker-compose
- java - 如何允许 WebView 在不丢失登录凭据的情况下始终控制登录状态?
- c# - 使用反射的实例
- angular - 重定向后保留尝试的 URL 参数
- python - 如何使用python将表格转换为字典?
- ios - 为什么不使用 removeDeliveredNotifications 删除通知?
- bash - sed:无法将 26 个项目写入标准输出:管道损坏
- mongodb - 在 MongoDB 上嵌套查找
- python - 如何在 python 中使用 Axes3D 绘制数据?
- php - 如何使 NetBeans IDE 9 与 PHP 一起工作?