【问题标题】:How do I get Redux state before the component re-renders?如何在组件重新渲染之前获取 Redux 状态?
【发布时间】:2020-03-04 16:30:13
【问题描述】:

由于 how data flows 通过 React-Redux 应用程序,在 React 组件重新渲染之前,在商店中更新的数据不可用。

我的问题是,在给定组件中,我想使用更新后的商店 重新渲染组件。我想做这样的事情:

import React, { Component } from "react";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";

import * as AActions from "../aactions";
import * as BActions from "../bactions";
import * as CActions from "../cactions";
class MyComponent extends Component<Props>{

    constructor(props){
        super(props);
        this.func = this.func.bind(this);
    };

    func(){
        // Add item to A
        this.props.addAItem("value");

        // Get id of newly added item in A
        let addedA = this.props.A.find(a => a.name === "value");

        // Insert new items in B with the id of A
        this.props.addBItem(addedA.id, "valueB");

        // etc...
    }

    render(){
        <div onClick={() => this.func()}>click me</div>
    }
}

function mapStateToProps(state, props){
    return {
        A: state.A,
        B: state.B,
        C: state.C
    };
}
function mapDispatchToProps(dispatch){
    return bindActionCreators({...AActions, ...BActions, ...CActions}, dispatch);
}

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

不起作用,因为 props 在 MyComponent 重新渲染之前不会更新。我不能打电话给this.props.A.find(a =&gt; a.name === "value");,因为道具不会有最近添加的“A”值。就我而言,我等不及 MyComponent 重新渲染。在 MyComponent 中访问最新状态的选项有哪些?

我做过类似的事情,但它绝对是可怕的,但它确实有效......

func(){
    if (this.props.step1){
        // Add item to A
        this.props.addAItem("value");

        this.props.setStep2();
    } else if (this.props.step2) {
        // Get id of newly added item in A
        let addedA = this.props.A.find(a => a.name === "value");

        this.props.setStep3();
    }
    // etc...
}

【问题讨论】:

  • 我不明白这个问题。 - 当 redux store 更新时,你的组件的 props 会发生变化,并且会发生重新渲染(假设你没有实现 shouldCompoentUpdate 方法)。为什么要在不重新渲染的情况下更改组件的内部状态?
  • @dwjohnston 这种思维模式背后的原因是所有动作都应该作为一个单元发生,我不能让 MyComponent 重新渲染,因为这样做需要我点击那个
    再次。我需要对状态进行多次更改(取出最近插入元素的 id)。
  • 组件重新渲染不会重置组件状态。只需在onclick上设置组件状态,然后dispatch?
  • @dwjohnston 我的组件依赖于商店的价值。 store 的值(映射为 props)在组件接收到新的 props(并且组件被重新渲染)之前不会更新。除了我的函数需要用户输入外,一切都可以正常工作,所以在我调用第一次调度后,组件重新渲染并且我的 func() 不会继续执行,这有意义吗?

标签: reactjs redux react-redux


【解决方案1】:

好的,如果我正确理解您的问题,您的 func 方法 addItemA 然后 addItemB 取决于 addItemA 的响应,addItemA 将是一个异步操作,因此在您添加项目时的 addItemA 操作中,您可以简单地从您的操作中返回承诺当解析返回新创建元素的 id 并在组件内部时,您可以在 then 块中处理为

func(){
    // Add item to A
    this.props.addAItem("value").then((id) => {
    // no need to find the id now
    // Insert new items in B with the id of A
    this.props.addBItem(id, "valueB");

    });


     // etc...
  }

希望对你有帮助

【讨论】:

  • 是的,我认为这应该可以解决问题,谢谢您的回答!
  • 如果答案有帮助,请考虑接受并投票,干杯:)
  • 它让我更进一步,但现在我看到“操作必须是普通对象。使用自定义中间件进行异步操作”。一旦我弄清楚更多细节,我想把它和这个问题放在一起并接受它。
  • 我认为你是从动作创建者返回函数,你可以使用 redux-thunk 来解决这个问题,因为默认情况下动作是纯 JS 对象,redux-thunk 允许你从动作创建者返回函数,希望它澄清
  • 谢谢@ibtsam。我最终采取了另一种可行的方法,请参阅我的答案以获得更多说明。感谢您的帮助。
【解决方案2】:

做了很多来回和测试,我遇到了很多墙试图弄清楚这一点,但最终还是弄明白了。这是您需要做的。

注意:这不被视为 React Redux 公共 API 的一部分,可能会在不通知的情况下中断。我们确实认识到社区有必要的用例,并将尝试使用户能够在 React Redux 之上构建额外的功能,但我们对上下文的特定使用被认为是实现细节。如果您有当前 API 未充分涵盖的其他用例,请提交问题以讨论可能的 API 改进。 - https://react-redux.js.org/using-react-redux/accessing-store#using-reactreduxcontext-directly

确保您的 react 包为 16.8.3 或更高版本。确保您的 react-redux 包为 7.1 或更高版本。您需要这些版本,因为新的方式(在 React 16.8.3 中)React 将 Context 传递给子组件。我们关心 Context,因为这个新的 React Context API 是 ReactReduxContext 的工作原理。

ReactReduxContext 是我们需要的魔法酱,以便在组件中获取商店的当前状态。请注意以下组件中的更改

import React, { Component } from "react";
import { bindActionCreators } from "redux";
import { connect, ReactReduxContext } from "react-redux"; // CHANGED!

import * as AActions from "../aactions";
import * as BActions from "../bactions";
import * as CActions from "../cactions";
class MyComponent extends Component<Props>{

    constructor(props){
        super(props);
        this.func = this.func.bind(this);
    };

    func(store){ // CHANGED!
        // Add item to A
        this.props.addAItem("value");

        // Get id of newly added item in A
        let addedA = store.getState().A.find(a => a.name === "value"); // CHANGED!

        // Insert new items in B with the id of A
        this.props.addBItem(addedA.id, "valueB");

        // etc...
    }

    // CHANGED!
    render(){
        <ReactReduxContext.Consumer>
            {({store}) => {
                return <div onClick={() => this.func(store)}>click me</div>
            }}
        </ReactReduxContext.Consumer>
    }
}

function mapStateToProps(state, props){
    return {
        A: state.A,
        B: state.B,
        C: state.C
    };
}
function mapDispatchToProps(dispatch){
    return bindActionCreators({...AActions, ...BActions, ...CActions}, dispatch);
}

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

神奇的是store.getState(),它返回更新的 Redux 存储。

我想指出我广泛研究了redux-thunk,但这种方法最终并没有满足我的需求。主要问题是在我的组件中使用了 bindActionCreators。因为我使用的是 bindActionCreators,所以我调用的任何操作都需要一个空对象,该对象会被分派到 Redux 存储。

我尝试了多种方法来尝试在操作中返回更新后的 Redux 状态,但由于我使用的是 bindActionCreators,因此我无法从给定操作返回 Redux 状态的值。获取更新的 Redux 存储状态的唯一方法是使用我上面概述的方法。

【讨论】:

    【解决方案3】:

    shouldComponentUpdate 应该可以解决问题

    【讨论】:

      猜你喜欢
      相关资源
      最近更新 更多
      热门标签