【问题标题】:Redux store doesn't update on first button clickRedux 商店不会在第一次单击按钮时更新
【发布时间】:2019-11-27 03:57:19
【问题描述】:

我想使用 redux,但仍然通过我的本地状态控制在 bootstrap-react-table 中呈现的内容。因此,在 componentDidMount 中,我正在获取我的数据,当我尝试通过按钮进行过滤时,单击我将 setState 设置为名为“itemsToDisplay”的字段,然后我想将其用作表中的数据。但是点击只在第二次起作用,当我在 render/componentDidMount 中记录状态时,它是未定义的。

我尝试了不同的条件来呈现表格的数据字段道具中的项目,但没有成功。我也尝试在 componentWillMount 中设置状态。

class Deliveries extends Component {
  constructor(props) {
    super(props);
    this.state = {
      itemsToDisplay: this.props.deliveries,
    };
  }

  componentDidMount() {
    this.props.getDeliveries();
    this.setState(prev => {
      return {
        ...prev,
        itemsToDisplay: this.props.deliveries,
      }
    })
  }

  filterUndelivered = () => {
    this.props.filterUndelivered();
    this.setState(prev => {
      return {
        ...prev,
        itemsToDisplay: this.props.undelivered_items,
      }
    })
  };

  getFilters = () => {
    return (
      <div>
        <Button className="m-1" color="primary">By time</Button>
        <Button className="m-1" color="primary" onClick={ this.filterUndelivered }>Not delivered</Button>
      </div>
    );
  };

  render() {
    const { itemsToDisplay } = this.state;

    const options = {
      insertBtn: this.createCustomInsertButton,
      searchField: this.createCustomSearchField,
    };

    return (
      <div className="animated fadeIn">

        <div className="d-flex justify-content-between">
          <div className="font-weight-bold mt-2">Deliveries Monitor</div>
          <div className="d-flex justify-content-end">
            {this.getFilters()}
          </div>
        </div>
        <BootstrapTable
          data={ itemsToDisplay ? itemsToDisplay : this.props.deliveries }
          version="4"
          search
          hover
          pagination
          bordered={false}
          headerStyle={{ background: "#20a8d8" }}
          bodyStyle={{ cursor: "pointer"}}
          options={ options }
        >
          <TableHeaderColumn isKey dataField="delivery_id">Delivery#</TableHeaderColumn>
          <TableHeaderColumn dataField="seller">Seller</TableHeaderColumn>
          <TableHeaderColumn dataField="address">Address</TableHeaderColumn>
          <TableHeaderColumn dataField="site">Site</TableHeaderColumn>
          <TableHeaderColumn dataField="end_of_window">End of window</TableHeaderColumn>
          <TableHeaderColumn dataField="due_date">Due date</TableHeaderColumn>
          <TableHeaderColumn dataField="status">Status</TableHeaderColumn>
        </BootstrapTable>
      </div>
    )
  }
}

const mapStateToProps = state => {
  return {
    deliveries: state.deliveriesReducer.deliveries,
    undelivered_items: state.deliveriesReducer.undelivered_items,
  }
};

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({ getDeliveries, filterUndelivered }, dispatch);
};

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

当数据道具的条件正确时,预期的结果是能够在第一次点击时进行过滤。

【问题讨论】:

  • 我过去也遇到过同样的问题。你检查过 Redux 的数据流吗?
  • 我做到了。从操作到从减速器返回的所有过程中,数据看起来都很好,并且组件可以正确接收它。出于某种原因,第一次单击将“itemsToDisplay”保留为未定义,然后在第二次单击时正常工作。
  • 有没有可能是同步问题?
  • 尝试使用 componentWillReceiveProps(nextProps)

标签: reactjs redux jsx state-management react-bootstrap-table


【解决方案1】:

试试这个,可能会有帮助

...
componentDidMount() {
    this.props.getDeliveries();    
}
...
componentWillReceiveProps(recievedProps) {
    if (this.props.deliveries != recievedProps.deliveries) {
        this.setState({
            itemsToDisplay: recievedProps.deliveries
        })
    }
}
...

【讨论】:

    【解决方案2】:

    为什么您的组件中有另一个事实来源(状态)?基本上,将 props 存储在组件状态中是一种不好的做法(当然有一些情况,但我认为您在这里不需要它)。

    我认为您的组件应该只接收一个 items 属性,它会显示已交付或未交付的项目。您的操作将负责根据您在 getDeliveries/filterUndelivered 操作中设置的某种过滤器在您的 items 属性中传递已交付或未交付的项目。

    这样,您将始终将 items 道具传递给您的 BootstrapTable data 道具,并且您的 redux 将负责在您的组件 items 道具中传递正确的项目(已交付或未交付)。

    这种方法的另一个优点是,如果您要为您的项目添加另一种过滤器(比如说搜索查询),那么您只需扩展您的 redux 过滤器状态并添加 searchQuery 属性。这样您就可以轻松地将新过滤器应用于您的项目,并且您的组件基本上不需要任何更改。

    Here 是一个简单的待办事项示例,具有简单的过滤功能,您可以将其应用于您的案例。

    【讨论】:

      【解决方案3】:

      在将数据加载到表之前执行简单的检查数据是否可用

      {
        itemsToDisplay.lenght > 0 &&
          <BootstrapTable
                    data={ itemsToDisplay }
                    version="4"
                    search
                    hover
                    pagination
                    bordered={false}
                    headerStyle={{ background: "#20a8d8" }}
                    bodyStyle={{ cursor: "pointer"}}
                    options={ options }
                  >
                    <TableHeaderColumn isKey dataField="delivery_id">Delivery#</TableHeaderColumn>
                    <TableHeaderColumn dataField="seller">Seller</TableHeaderColumn>
                    <TableHeaderColumn dataField="address">Address</TableHeaderColumn>
                    <TableHeaderColumn dataField="site">Site</TableHeaderColumn>
                    <TableHeaderColumn dataField="end_of_window">End of window</TableHeaderColumn>
                    <TableHeaderColumn dataField="due_date">Due date</TableHeaderColumn>
                    <TableHeaderColumn dataField="status">Status</TableHeaderColumn>
                  </BootstrapTable>
      }
      

      【讨论】:

        【解决方案4】:

        尝试修改您的代码,如下所示:

          filterUndelivered = () => {
            this.props.filterUndelivered();
          };
        
          componentWillReceiveProps = nextProps => {
            if (nextProps.undelivered_items !== undefined) {
              this.setState({ itemsToDisplay: nextProps.undelivered_items });
            }
          };
        

        同时在浏览器中安装 Redux 开发工具并分析应用程序状态。它可能会让您更深入地了解问题。

        铬:https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd

        火狐:https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/

        【讨论】:

        • 我试过了,逻辑还是一样:第一次点击不行,第二次点击有效。
        • 您是否厌倦了开发工具...您是否在状态下看到第一次点击的数据?
        • 是的,在 Redux devtools 中,状态会在第一次单击和 store 正确更新后发生变化。
        • 第一次点击时在componentWillReceiveProps中获得回调?..添加一些控制台日志并查看
        • 实际上,我设法通过@prasobh.kollat​​tu 的回答解决了这个问题,但请注意,setState 函数还需要一个传播才能准确地了解先前的状态:componentWillReceiveProps = nextProps =&gt; { if (nextProps.undelivered_items !== undefined) { this.setState(prev =&gt; { return { ...prev, itemsToDisplay: nextProps.undelivered_items } }); } };
        猜你喜欢
        • 2019-11-05
        • 2021-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-17
        • 1970-01-01
        • 2018-04-09
        • 2020-02-06
        相关资源
        最近更新 更多