Redux 商店不会在第一次单击按钮时更新

Posted

技术标签:

【中文标题】Redux 商店不会在第一次单击按钮时更新【英文标题】:Redux store doesn't update on first button click 【发布时间】: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) 【参考方案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 ); ;

以上是关于Redux 商店不会在第一次单击按钮时更新的主要内容,如果未能解决你的问题,请参考以下文章

当我更新商店时 Redux 不会重新呈现

不使用按钮单击更新串行数据

Redux 状态在下一个 js 调度后不会改变

单击时更新 React 和 Redux 中的数组中的数据

如何在 redux 状态更新时自动刷新组件

在触发单击 Extjs 3.4 时重新加载 ComboBox 存储