My useSelector variable is printing Undefined even when Reducer has returned the value

Asked

Viewed 172 times

-1

I have this saga that performs an http request and performs a Dispatch on my Reducer:

// worker Saga: will be fired on GET_FILIAIS_REQUEST actions
function* fetchFiliais(action) {
    try {
        const data = yield call(LoginServices.fetchFiliaisApi);
        yield put(allActions.loginActions.receiveFilialData(data));
    } catch (e) {
        yield put({type: 'FETCH_FILIAIS_FAILED', message: e.message})
    }
}

/*
  Starts fetchFiliais on each dispatched `GET_FILIAIS_REQUEST` action.
*/

export default function* loginSaga() {
    yield takeEvery("GET_FILIAIS_REQUEST", fetchFiliais);
}

In my login component I perform a Dispatch to call this saga:

const Login = props => {
  const dispatch = useDispatch()
  const filiais = useSelector(state => state.filiais)
  useEffect(() => {
    dispatch({type: 'GET_FILIAIS_REQUEST'})
    setTimeout(function(){ console.log(filiais); }, 5000);
  }, [dispatch, filiais])

This is my Return. In my console.log() you are correctly printing the type and payload, including printing "enter correct case":

const currentUser = (state = {}, action) => {
    console.log(action.type)
    console.log(action.payload)

    switch(action.type){
        case "SET_USER":
            return {
                ...state,
                user: action.payload,
                loggedIn: true
            }
        case "LOG_OUT":
            return {
                ...state,
                user: {},
                loggedIn: false
            }
        case "RECEIVE_FILIAL_DATA":
            console.log('enter correct case')
            return {
                ...state,
                filiais: action.payload
            }
        default:
            return state
    }

But my console.log() that I put in the branch variable is printing Undefined. Because?

This is my index.js:

import loginSaga from './pages/login/login-form/saga'

// create the saga middleware
const sagaMiddleware = createSagaMiddleware()

const store = createStore(
    rootReducer,
    applyMiddleware(sagaMiddleware)
)

// then run the saga
sagaMiddleware.run(loginSaga)

ReactDOM.render(
    <Provider store={store}>
        <Router>
            <Route path="/" component={App} />
        </Router>
    </Provider>, document.getElementById('root'));

This is my root Reducer:

import currentUser from './login'
import { combineReducers } from 'redux'

const rootReducer = combineReducers({
    currentUser
})

export default rootReducer
  • Try to replace your const filiais = useSelector(state => state.filiais) for const filiais = useSelector(state => state.currentUser.filiais) and say what happens, please...

  • @Felipeavelar printa the correct value however useEffect is called several times, if I take the variable Dispatch and branches of the second parameter of useEffect is called only once, however the value is not printed...

1 answer

3


There are two unrelated problems in your code, so I’m going to split the answer into parts:

How your state works

First, you are trying to seek membership value directly in your Return with the line:

const filiais = useSelector(state => state.filiais)

your state, as you described in the question, is actually composed of a higher state currentUser and this will contain loggedIn, filias and user. Therefore, to access affiliates by useSelector, you need to use:

 const filiais = useSelector(state => state.currentUser.filiais)

This will effectively return the affiliations of the Redux state.

useEffect should NOT always be run

Note that in your Login component, you are running the useEffect where there is a change in dispatch and in filias:

useEffect(() => {
  dispatch({type: 'GET_FILIAIS_REQUEST'})
  setTimeout(function(){ console.log(filiais); }, 5000);
}, [dispatch, filiais]) //Aqui você atrelá efeitos quando houverem alterações em dispatch ou filias

However, note that in the body of this useEffect you launch a request for affiliates, which, if successfully completed, will cause a change in affiliates, which will consequently trigger the effect hook, which will launch the Dispatch, which will cause the change of affiliates in case of success, which... Understand? This will cause your program to constantly launch requests to update affiliates until a failure occurs. To solve this problem you need to perform the effect only in creation of your component, for this, you must update the useEffect for:

useEffect(() => {
  dispatch({type: 'GET_FILIAIS_REQUEST'})
  setTimeout(function(){ console.log(filiais); }, 5000);
}, [])

Since when you attach an empty vector to useEffect, it will only perform on component assembly (analogous to the old componentDidMount()), this will cause your affiliates to be updated only once and consequently either you will have all affiliates or you should do the error handling, creating the necessary action to do so in your Return (with the action FETCH_FILIAIS_FAILED that you created).

  • Thanks for the excellent explanation. When I remove Dispatch and branches from [] my console.log() again Undefined. Another thing I have to do when I withdraw them is to add a comment to my Eslint: //Eslint-disable-next-line React-Hooks/exhaustive-deps you can help me with this Undefined?

  • Actually you are entering my address in the case "RECEIVE_FILIAL_DATA" but it is printedUndefined

  • What is Undefined? The payload or affiliates? Remembering that if your request takes more than 5s to be processed, in fact it will be printed Undefined on the.log console of the timeout...

  • 1

    About the exhaustive-deps rule, there is a thread of long discussion in create-React-app about suppressing that rule when you in fact does not need the effect to be assisted by the. (:

Browser other questions tagged

You are not signed in. Login or sign up in order to post.