javascript - 如何在不同的 ReactJS 组件实例中拥有不同的数据?

标签 javascript reactjs redux

假设我有 2 <Logs/>成分。它们仅在其父级 <Block/> 时显示已被点击。每个<Block/>只有一个<Logs/>但会有很多<Blocks/>在页面上。

class Block extends React.Component {

    toggleExpanded() {

        this.setState({
            isExpanded: !this.state.isExpanded
        });

    }

    render() {

        let blockId = // ...

        return (
            <div>
                <button type="button" onClick={() => this.toggleExpanded()}>Toggle</button>
                {this.state.isExpanded && <Logs blockId={blockId} />}
            </div>
        );

    }

}

export default Block;

作为<Logs/>创建完成后,我想使用 Redux 从服务器获取数据。可能有很多<Logs/>有一天,我不想一开始就加载所有数据,只加载需要的数据。

class Logs extends React.Component {

    componentDidMount() {

        if (!this.props.logs) {
            this.props.fetchBlockLogs(this.props.blockId);
        }

    }

    render() {

        return (this.props.logs && this.props.logs.length)
            ? (
                <ul>
                    {this.props.logs.map((log, i) => <li key={i}>{log}</li>)}
                </ul>
            )
            : (
                <p>Loading ...</p>
            );

    }

}

SupportLogs.defaultProps = {
    logs: null
}

const mapStateToProps = (state) => ({
    logs: state.support.logs
});

const mapDispatchToProps = (dispatch, ownProps) => ({
    fetchBlockLogs: (blockId) => {
        dispatch(ActionTypes.fetchBlockLogs(blockId));
    }
});

export default connect(mapStateToProps, mapDispatchToProps)(SupportLogs);

目前,当我切换一位家长时 <Block/>关闭然后重新打开,数据会被记住。这是一个很好的功能 - 数据不会经常更改,并且本地缓存是加速页面速度的好方法。我的问题是,当我打开第二个 <Block/> 时,数据来自第一个<Logs/>显示。

我的问题是:如何为 <Logs/> 的新实例加载新数据?

我每次都必须重新加载数据吗?如果是这样,我可以清除logs吗?属性以便我恢复加载动画?

最佳答案

也许考虑将商店中的日志更改为一个对象,其中加载的日志由 block ID 键入:

logs: {
 'someBlockId': [
   'some logline', 
   'some other logline'
 ]
]

让你的reducer通过 block id将任何请求的日志添加到这个对象中,这样当你请求它们时,它们就会被缓存在你的存储中(顺便说一句,我真的很喜欢你的组件调度一个 Action 来触发其他地方的数据获取,作为副作用,而不是在组件内部执行获取数据:))。

此 reducer 假设所获取的数据在一个操作中分派(dispatch),表示它已收到特定 block 的日志,{type: 'UPDATE_LOGS', blockId: 'nicage', returnedLogsForBlock: ['oscar ', '获胜', ' Actor ']}

logsReducer: (prevState, action) => {
  switch(action.type)
    case 'UPDATE_LOGS':
      return Object.assign({}, prevState, {
        [actions.blockId]: action.receivedLogsForBlock
      })
    default: return prevState
  }
}

在您的组件中,您现在可以通过 id 查找它们。如果日志对象中没有定义所需的 block ,那么您知道您需要发送加载操作,并且还可以同时显示加载器

class Logs extends React.Component {

  componentDidMount() {
    const {logs, blockId} = this.props
    if (!logs[blockId]) {
      this.props.fetchBlockLogs(blockId);
    }
  }

  render() {
    const {logs, blockId} = this.props
    return (logs && logs[blockId]) ? (
        <ul>
          {logs[blockId].map((log, i) => <li key={i}>{log}</li>)}
        </ul>
      ) : (
        <p>Loading ...</p>
      )
  }

}

这还有一个额外的好处,即logs[blockId]未定义,意味着未加载,因此可以区分需要加载的内容。已加载,并且已经加载但有空日志,您的原始版本会误认为需要加载

关于javascript - 如何在不同的 ReactJS 组件实例中拥有不同的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47653075/

相关文章:

javascript - 删除事件监听器不工作

javascript - 在绝对 div 位置自动扩展 textarea 无法正确收缩

javascript - 当元素在屏幕中占 60% 时,WOW.js 开始动画

javascript - 如何在将按钮(Material UI)动态设置为禁用后更改其颜色?

javascript - 在 Storybook 中全局隐藏插件选项卡

reactjs - combineReducers 不推断类型

javascript - 匹配的路由在路由哈希更改时不会更改

javascript - 为什么这个 Javascript 代码块中需要 ()?

reactjs - 如何使用 React js 翻转网络摄像头?

javascript - React 复选框不更新