Ad

Redux Async Actions And View Updates

- 1 answer

I'm trying to implement a login form for a website, it's my first project on React so I'm quite a beginner.

To do so, I use socket.io-client inside my redux reducer. The thing is, it doesn't update the local props correctly.

Here's the code of my view:

const mapStateToProps = state => {
    return {
        profile: state.profileReducer.profile
    }
}

const mapDispatchToProps = dispatch => {
    return {
        dispatch: action => {
            dispatch(action)
        }
    }
}

...

handleConnection = () => {
    const { profile } = this.props

    this.props.dispatch({ type: 'CONNECT_USER' })

}

...

export default connect(mapStateToProps, mapDispatchToProps)(LoginPage)

And here's the reducer's action:

import io from 'socket.io-client'

const host = [SERVER_URL]

const socketConnection = io.connect(host, {path: [PATH], secure: true})

const initialState = {
    profile: {
        token: null,
        username: '',
        password: ''
    }
}

function profileReducer(state = initialState, action) {
    switch(action.type) {

        ...

        case 'CONNECT_USER':
            let tempProfile = {...state.profile}

            socketConnection.emit('login', tempProfile.username + ';' + tempProfile.password)

            socketConnection.on('check', msg => {
                if (msg !== null && msg !== '')
                    tempProfile.token = msg

                return {
                    ...state,
                    profile: tempProfile
                }
            })

            return state

        ...
    }
}

The 'check' socket action return a message containing the user connection token which I need to store to make sure the connection is done and allowed. The thing is, it doesn't update the store value. If I update directly the reducer's state instead of the temporary profile, it partly works : the view props isn't properly updated but a 'console.log(profile)' in a 'setInterval' inside the 'handleConnection' function shows the token value (but the props inside the Chrome React Inspector isn't updated).

I really don't understand what's going on. I suppose the socket.io 'on' function isn't done before the 'return' of my action but I don't know how to handle it.

Does someone as any idea how I could solve this problem ?

Thanks !

Ad

Answer

Reducers are always synchronous in nature. If you want to perform an async operation (like the socket connection you are trying to establish) in your reducer then you need to use a middleware like Thunk or Saga to achieve the same.

In your case it is always returning the existing state from the last return statement.

Ad
source: stackoverflow.com
Ad