Anfal Anfal - 9 days ago 6
React JSX Question

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?

Answer

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.