【问题标题】:React-Redux and Connect - Why is my state not updating on click?React-Redux 和 Connect - 为什么我的状态在点击时没有更新?
【发布时间】:2017-12-01 04:50:10
【问题描述】:

我是 redux 的新手,正在编写一个简单的投票前端,它允许用户对他们最喜欢的框架(Angular、React、Vue)进行投票。当用户点击他们想要投票的框架时,我打算将商店中的投票增加一。

我正在使用 combineReducersconnect 来促进这一点。但是,每次点击后,状态总是落后一票。一次投票后状态为 0。点击 2 次后,投票状态为 1,依此类推。

这是我的 index.js 文件,我在其中创建商店并呈现应用程序

//index.js
const combinedReducers = combineReducers({
    "votes": votesReducer,
    "currentPercentages": currentPercentageReducer,
    "pastPercentages": pastPercentageReducer
});

let store = createStore(combinedReducers);

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>, 
    document.getElementById('root')
);

这是我的行动

export function voteAction(framework){
    return {
        type: "VOTE",
        payload: framework
    }
}

下面是更新投票状态的相关reducer

const initialVoteState = { angular: 0, react: 0, vue: 0 };

export function votesReducer(state=initialVoteState, action){
    switch(action.type){
        case "VOTE":
            if (action.payload === 'angular'){
                return Object.assign({}, state, {
                    angular: state.angular + 1
                });
            } else if (action.payload === 'react'){
                return Object.assign({}, state, {
                    react: state.react + 1
                });
            } else {
                return Object.assign({}, state, {
                    vue: state.vue + 1
                });
            }
        default:
            return state;
    }

}

最后,这是我拥有的组件,它具有点击处理程序,以方便投票并相应地更新状态。

@connect(state => {
    return {
        votes: {
            angular: state.votes.angular,
            react: state.votes.react,
            vue: state.votes.vue
        },
        currentPercent: {
            angular: state.currentPercentages.angular,
            react: state.currentPercentages.react,
            vue: state.currentPercentages.vue
        },
        pastPercent: {
            angular: state.pastPercentages.angular,
            react: state.pastPercentages.react,
            vue: state.pastPercentages.vue
        }
    }
})
export default class InfoArea extends Component {
    constructor(props){
        super(props);
        this.votedAngular = this.votedAngular.bind(this);
        this.votedReact = this.votedReact.bind(this);
        this.votedVue = this.votedVue.bind(this);
    }

    votedAngular(){
        this.props.dispatch(voteAction('angular'));
        console.log(this.props.votes.angular);
        //the log above will output 0 after the first vote is cast, 1
        after the second vote is cast etc. Why is this the case? Should 
        it not be set to the correct value here since the action has 
        already been dispatched?

    }

    votedReact(){
        this.props.dispatch(voteAction('react'));
    }

    votedVue(){
        this.props.dispatch(voteAction('vue'));
    }

    render(){
        return (
        <div className="info-container">
            <img 
                style={{"marginTop":"25px"}} 
                className="app-img" 
                src={require("../../public/brainbulb.svg")}>
            </img>
            <h2 className="wide">What is your favourite front-end framework in 2017?</h2>
            <h4 style={{"marginTop": "0"}}>Click an image below to vote!</h4>
            <div className="row">
                <div className="images-container">
                    <img
                        onClick={this.votedAngular} 
                        className="framework-logo" 
                        src={require("../../public/angular.png")}>
                    </img>
                    <img 
                        onClick={this.votedReact}
                        className="framework-logo" 
                        src={require("../../public/react.png")}>
                    </img>
                    <img 
                        onClick={this.votedVue}
                        className="framework-logo"
                        src={require("../../public/vue.png")}
                    ></img>
                </div>
            </div>
        </div>
        );
    }
}

另外值得注意的是,当我投票并在浏览器控制台中查看我的商店状态时,它是准确的。然而,我的组件仍然落后一票。任何帮助将不胜感激。

【问题讨论】:

  • 我不确定 console.log 是否是检查状态/存储的最佳方式。我认为如果您应该查看 redux chrome 扩展,那么您可以更清楚地看到 redux 中发生了什么。您的代码似乎正确。

标签: reactjs redux react-redux


【解决方案1】:

无法立即更新状态的原因是因为更新存储的操作是异步写入的

votedAngular(){
    this.props.dispatch(voteAction('angular'));
    console.log(this.props.votes.angular);
}

表示您正在尝试在触发操作后立即检查该值。如果您想测试该值,我建议您在componentWillReceiveProps 函数中进行

componentWillReceiveProps(nextProps) {
   console.log(nextProps.votes.angular);
}

但是,对于需要测试 redux 值的此类操作,redux-devtools-extension 是一个理想的工具。

【讨论】:

  • 所以每次写入存储都是异步操作?我没有访问任何服务器来获取数据或任何东西,我只是将计数器增加 1。为什么这是异步的?
  • 对存储的更新是异步发生的,在更新的数据可用之前,您的 console.log() 会被处理。此外,更新商店可能是一项昂贵的操作,并且使其同步可能会使浏览器无响应。
  • 感谢 Shubham,我已经确认 componentWillReceiveProps 中的状态是正确的。如果我想做类似部署“castVote”操作,那么在商店更新后立即部署“updatePercentages”操作,我应该使用 thunk 来执行此操作吗?
猜你喜欢
  • 2017-01-25
  • 1970-01-01
  • 2021-05-09
  • 1970-01-01
  • 2021-09-02
  • 2023-03-31
  • 2018-03-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多