Search code examples
reactjsreduxmernredux-toolkit

Cannot read properties of undefined (reading 'ids') , while using globalSelectors,simpleSelectors of redux toolkit in createEntityAdapter


I am Learning Redux Toolkit and using createEntityAdapter for a simple todo app. the problem is that I am getting errors whenever I try to access the todos from globalselectors or/and simple selectors of the todoAdapter.

I've created a CodeSandBox for this

This is the todoReducer code where I am setting


const todosAdapter = createEntityAdapter({
  selectId: (todo) => todo._id,
});

const initialState = {
  fetching: true,
  error: null,
  addingNew: false,
};

const todosSlice = createSlice({
  name: 'todos',
  initialState: todosAdapter.getInitialState(initialState),
  reducers: {
    pushNewTodo: todosAdapter.addOne,
    addManyTodos: todosAdapter.addMany,
    removeTodo: todosAdapter.removeOne,
    editTodo: todosAdapter.updateOne,
  },
  extraReducers: { ... }
})

//* Errror in this line , 
export const globalTodosReducers = todosAdapter.getSelectors((st) => st.todos);
export const simpleTodosReducers = todosAdapter.getSelectors();

export const {
  addTodo,
  removeTodo,
  toggleTodo,
  editTodo,
  clearTodos
} = todosSlice.actions;
export default todosSlice.reducer;

And when I want to use simpleSelectors , I get error in that also

// TodoApp.js
function TodoApp() {
  .
  .
  .
  // * Error in these lines
  // const todos = globalTodosReducers.selectAll();
  const todos = simpleTodosReducers.selectAll();


.
.
.

error is

Cannot read properties of undefined (reading 'ids')

Solution

  • The object returned by getSelectors contains many selector functions. Each one requires you to pass in the state object that contains the data you want to select from. You had the right idea here:

    todosAdapter.getSelectors((st) => st.todos)
    

    This tells the entity adapter to access the todos property of whatever object is passed in to the selector functions in order to get the data managed by the adapter.

    When you call a selector, pass in your application's root state:

    const todos = globalTodosReducers.selectAll(store.getState());
    

    In the context of React, react-redux's useSelector function will do this for you:

    const todos = useSelector(globalTodosReducers.selectAll);