React-Redux state of changed value is not refrected on change

Viewed 1086

The state of the App is comprised of 2 independent states managed by: modelA, modelB reducers. Ignore modelB. For modelA i have an action - setInput. This action is used in the onChange listener of component Whatever to set inputVal val to whatever.

Whatever listener should also display the inputVal, but that doesn't happen. The changes to inputVal are not reflected.

Debugging shows that the state is indeed modified - whatever is entered in the input element of Whatever, is being save in the state. It's just that the stateToProps mapper is not invoked again.

What am i doing wrong?

var INPUT = 'INPUT';
var setInput = (val = '') => ({
    type: INPUT,
    payload: val
})

var modelA = (state = {test1: '', test2: false, inputVal: ''}, action) => {
    switch (action.type) {
        case this.INPUT:
            state.inputVal = action.payload;
            return state
        default:
            return state
    }
}
var modelB = (state = {test1: '', content: ''}, action) => {
    switch (action.type) {
        default:
            return state
    }
}

var stateToProps = state => {
    return {
        storeValue: state.modelA.inputVal
    }
}
var dispatchToProps = dispatch => {
    return {
        setStoreVal: (val) => {
            dispatch(setInput(val))
        }
    }
}

class App extends React.Component {
    constructor(props) {
        super(props);
        this.store = Redux.createStore(Redux.combineReducers({modelA, modelB}));
    }
    render() {
        return e(
            ReactRedux.Provider, {store:this.store},
                e('div', null, "App", 
                    e(ReactRedux.connect(stateToProps, dispatchToProps)(Whatever), null)
                )
            );
    }
}
class Whatever extends React.Component {
    constructor(props) {
        super(props);
        this.state = {val:0}
        this.listener = this.listener.bind(this);
    }
    listener(evt) {
        this.props.setStoreVal(evt.currentTarget.value);
        this.setState({val:evt.currentTarget.value});
    }

    render() {
        return e(
            'div', null,
            e('p', null, this.props.storeValue),
            e('input', {onChange:this.listener, val:this.state.val})
            );
    }
}
1 Answers

Redux assumes that you never mutate the objects it gives to you in the reducer. Every single time, you must return the new state object. Even if you don't use a library like Immutable, you need to completely avoid mutation.

Never mutate reducer arguments

var modelA = (state = {test1: '', test2: false, inputVal: ''}, action) => {
    switch (action.type) {
        case this.INPUT:
            return {...state, inputVal: action.payload}; // return new one
        default:
            return state
    }
}
Related