React-Redux 和 Connect - 为什么我的状态没有在点击时更新? [英] React-Redux and Connect - Why is my state not updating on click?

查看:80
本文介绍了React-Redux 和 Connect - 为什么我的状态没有在点击时更新?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

//index.jsconst combineReducers = combineReducers({投票":votesReducer,currentPercentages":currentPercentageReducer,过去百分比":过去百分比减少器});让 store = createStore(combinedReducers);ReactDOM.render(<提供者商店={商店}><应用程序/></提供者>,document.getElementById('root'));

这是我的行动

导出函数voteAction(framework){返回 {类型:投票",有效载荷:框架}}

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

const initialVoteState = { angular: 0, react: 0, vue: 0 };导出函数votesReducer(state=initialVoteState, action){开关(动作.类型){案例投票":if (action.payload === 'angular'){返回 Object.assign({}, state, {角度:state.angular + 1});} else if (action.payload === 'react'){返回 Object.assign({}, state, {反应:state.react + 1});} 别的 {返回 Object.assign({}, state, {vue: state.vue + 1});}默认:返回状态;}}

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

@connect(state => {返回 {投票:{角度:state.votes.angular,反应:state.votes.react,vue: state.votes.vue},当前百分比:{角度:state.currentPercentages.angular,反应:state.currentPercentages.react,vue: state.currentPercentages.vue},过去百分比:{角度:state.pastPercentages.angular,反应:state.pastPercentages.react,vue: state.pastPercentages.vue}}})导出默认类 InfoArea 扩展组件 {构造函数(道具){超级(道具);this.votedAngular = this.votedAngular.bind(this);this.votedReact = this.votedReact.bind(this);this.votedVue = this.votedVue.bind(this);}投票角(){this.props.dispatch(voteAction('angular'));控制台日志(this.props.votes.angular);//第一次投票后,上面的日志会输出0,1在第二次投票之后等等.为什么会这样?应该此处未将其设置为正确值,因为该操作已已经发货了?}投票反应(){this.props.dispatch(voteAction('react'));}投票(){this.props.dispatch(voteAction('vue'));}使成为(){返回 (<div className="信息容器"></img><h2 className="wide">2017年你最喜欢的前端框架是什么?</h2><h4 style={{"marginTop": "0"}}>点击下方图片进行投票!</h4><div className="row"><div className="images-container"></img></img>

);}}

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

解决方案

之所以不能立即更新状态是因为更新 store 的操作是异步写入的

votedAngular(){this.props.dispatch(voteAction('angular'));控制台日志(this.props.votes.angular);}

表示您正在尝试在触发操作后立即检查该值.如果你想测试这个值,我建议你在 componentWillReceiveProps 函数

中进行

componentWillReceiveProps(nextProps) {控制台日志(nextProps.votes.angular);}

然而,对于需要测试 redux 值的操作,redux-devtools-extension 是一个理想的工具.

I am new to redux and am writing a simple voting front end which allows the user to vote on their favourite framework (Angular, React, Vue). When a user clicks on a framework they would like to vote for, I intend to increment the votes in the store by one.

I'm using combineReducers and connect to facilitate this. However, after each click, the state is always one vote behind. After one vote the state is at 0. After 2 clicks, the vote state is at 1, etc.

Here is my index.js file wherein I create my store and render the app

//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')
);

Here is my action

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

Below is the relevant reducer for updating the vote state

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;
    }

}

Finally, here is the component I have which has the click handler to facilitate casting a vote and updating the state accordingly.

@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>
        );
    }
}

Also worth noting that when I cast a vote and view my store state in the browser console it is accurate. Yet, my component remains one vote behind. Any help would be greatly appreciated.

解决方案

The reason you are not able to the the updated state immediately is because the operation of updating the store is async and writing

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

means that you are trying to check for the value as soon as the action is triggered. If you want to test the value, I would suggest you do it in the componentWillReceiveProps function

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

However, for such operations where you need to test for redux values, redux-devtools-extension is an ideal tool.

这篇关于React-Redux 和 Connect - 为什么我的状态没有在点击时更新?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆