Anfal
Anfal

Reputation: 344

Redux/React is not returning the updated state on first dispatch

I am learning redux/react and I am developing a sample application to understand it, for experiment I am trying to update the checkbox checked property using reducer.

My reducer is as follows.

const check_box_state = (state = false, action) => {
switch(action.type) {
    case ActionNames.TOGGLE_CHECKBOX:
        return !state;
    default:
        return state;
}
};

then I am using react-redux connect method to pass this reducer to my component via following code.

const StateFullSignInPanel = connect(
function mapStateToProps(state) {
    return {redux_state: state};
},
function mapDispatchToProps(dispatch) {
    return {
        toggle_check_box: (previous_state) => dispatch(toggleCheckbox(previous_state))
    }
}
)(SignInPanel);

export default StateFullSignInPanel;

Finally my component is as follows.

class SignInPanel extends Component {

    constructor(props) {
        super(props);
        this.state = {
            checkbox_state: this.props.redux_state.generic_reducers.check_box_state
        };
        this.handleRememberMeState = this.handleRememberMeState.bind(this);
        this.handleSignInClick = this.handleSignInClick.bind(this);
    }

    handleRememberMeState() {
        let previous_checkbox_state = this.state.checkbox_state;
        this.props.toggle_check_box(previous_checkbox_state);
        let new_checkbox_state = this.props.redux_state.generic_reducers.check_box_state;
        this.setState({
            checkbox_state: new_checkbox_state
        });
    }

    handleSignInClick() {
    }

    render() {
        return <div className="ui card sign_in_card">
            <div className="ui input input_fields">
                <input type="text" placeholder="Email or username"/>
            </div>
            <div className="ui input input_fields">
                <input type="text" placeholder="Password"/>
            </div>
            <div className="ui checkbox remember_me_checkbox">
                <input
                    type="checkbox"
                    id="remember_me"
                    onChange={this.handleRememberMeState}
                    checked={this.state.checkbox_state}
                />
                <label htmlFor="remember_me">Remember me</label>
            </div>
            <div className="sign_in_button">
                <button className="ui green button" onClick={this.handleSignInClick}>
                    Sign in
                </button>
            </div>
        </div>
    }
}

export default SignInPanel;

State of the checkbox start to update successfully and as expected only after the second time I click it, for the first time setState gets the default state from the reducer and checkbox remains unchecked. I am also using loggerMiddleware from redux-logger and it shows that the state is successfully updated from false to true after the action dispatch but even after that new state I receive is false. What am I doing wrong?

Upvotes: 0

Views: 317

Answers (1)

yadhu
yadhu

Reputation: 15632

Try this approach (gotten rid off the internal state and now checkbox is controlled using the exising key on redux state):

import { toggleCheckbox } from './actions';

class SignInPanel extends Component {

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

    handleRememberMeState() {
        this.props.toggle_check_box(this.props.check_box_state);
    }

    handleSignInClick() {
        // ...
    }

    render() {
        return <div className="ui card sign_in_card">
            <div className="ui input input_fields">
                <input type="text" placeholder="Email or username"/>
            </div>
            <div className="ui input input_fields">
                <input type="text" placeholder="Password"/>
            </div>
            <div className="ui checkbox remember_me_checkbox">
                <input
                    type="checkbox"
                    id="remember_me"
                    onChange={this.handleRememberMeState}
                    checked={this.props.check_box_state}
                />
                <label htmlFor="remember_me">Remember me</label>
            </div>
            <div className="sign_in_button">
                <button className="ui green button" onClick={this.handleSignInClick}>
                    Sign in
                </button>
            </div>
        </div>
    }
}

export default connect(
  (state) => ({ check_box_state: redux_state.generic_reducers.check_box_state }),
  { toggle_check_box: toggleCheckbox }
)(SignInPanel);

As per ^^this implementation the redux state is now directly connected to SignInPanel. So we won't need the code for mapStateToProps and mapDispatchToProps to create StateFullSignInPanel.

Upvotes: 1

Related Questions