React-Redux 和 Connect - 为什么我的状态没有在点击时更新?

IT技术 reactjs redux react-redux
2021-05-03 19:41:33

我是 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>
        );
    }
}

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

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是一个理想的工具。