Need help accessing state from useSelector, state disappears after rerender

Viewed 49

I'm new to this and I've been trying to access the state from useSelector and I can get it when I console.log but then it comes up undefined as soon as I rerender. I'm guessing I need useEffect but I'm not sure how to go about using it to access the state. Any help would be much appreciated. Thank you!

*Update: I can populate the list of todos with this code but as soon as I refresh the page it disappears and comes up as undefined. can someone please help me?

index.js

import React, {useEffect, useState} from "react";
import { useSelector, useDispatch } from "react-redux";
import {getTodos} from './actions';
import { useInjectReducer } from '../../utils 2/injectReducer';
import { useInjectSaga } from '../../utils 2/injectSaga';
import reducer from './reducer';
import saga from './saga';

const key = 'todoList';

function TodoList() {
    useInjectReducer({key, reducer});
    useInjectSaga({key, saga});

    const dispatch = useDispatch();
    const [isLoading, setIsLoading] = useState(true);
    const todos = useSelector(state => state.todoList);
    console.log(todos.todos)

    useEffect(() => {
        function fetchTodo() {
            dispatch(getTodos());
            setIsLoading(false);
        }
        if (isLoading) {
            fetchTodo();
        }
    }, [dispatch, isLoading]);

    
    if (isLoading) return <b>Loading...</b>;

    if (!isLoading && todos.length === 0) {
        return <b>Please add a to do!</b>;
    }

    return (
        <div>
            {todos.map(todo => (
                <ul>
                    <li>{todo.todo}</li>
                </ul>
            ))}
        </div>
    );
}

export default TodoList;

reducer.js

import { 
    FETCH_TODOS,
    FETCH_TODOS_SUCCESS,
    FETCH_TODOS_ERROR, 
} from "./constants";


export const INITIAL_STATE = {
    todos: [],
    error: null
};

export default function todoReducer(state=INITIAL_STATE, action) {
    switch (action.type) {
        case FETCH_TODOS:
            return ({...state});
        case FETCH_TODOS_SUCCESS:
            return ({...state, todos: action.todos});
        case FETCH_TODOS_ERROR:
            return ({...state, todos: null, error: action.error});
        default:
            return state;
    }
}

saga.js

import {call, put, takeLatest} from 'redux-saga/effects';
import { FETCH_TODOS, FETCH_TODOS_SUCCESS, FETCH_TODOS_ERROR } from './constants';
import { fetchTodos } from './api';


export function* getTodos() {
    try {
        const response = yield call(fetchTodos);
        yield put({type: FETCH_TODOS_SUCCESS, todos: response.data});
    } catch (e) {
        yield put({type: FETCH_TODOS_ERROR, error: e.message});
    }
}



export default function* todoSaga() {
    yield takeLatest(FETCH_TODOS, getTodos);
}



1 Answers

I think you used the wrong property name. Where is state.todoList?

export const INITIAL_STATE = {
    todos: [],
    error: null
};

Just change todoList to todos like it is in your redux state:

const todos = useSelector(state => state.todos);
Related