Home > database >  Getting "Cannot read properties of undefined" error in Redux Toolkit app on querying Initi
Getting "Cannot read properties of undefined" error in Redux Toolkit app on querying Initi

Time:08-31

I am trying to create a basic Redux use-case to share state between 2 sibling components (SimpleFruit and FruitLabel). I cannot figure out why it keeps running into the error: Cannot read properties of undefined. Since I am setting the initial state to a string, it should not run into the undefined state issue AFAIK. Would really like to know what I am doing wrong.

P.S. I have created the project using npx create-react-app --template redux as suggested by the official docs, so configuration should work fine.

EDIT: As explained by Nils Hartmann in his comment below, I needed to use useSelector() on my components. Additionally the dispatch needed to be passed through a callback for immutability. The code below has been updated with the changes

app/store.js:

import { configureStore } from '@reduxjs/toolkit';
import fruitReducer from '../features/fruits/fruitSlice';

export const store = configureStore({
  reducer: {
    fruit: fruitReducer,
  },
});

State/Action/Reducer: features/fruits/fruitSlice.js

import { createSlice } from '@reduxjs/toolkit';

const initialState = {
  fruitname: 'pineapple',
};

export const fruitSlice = createSlice({
    name: 'fruit',
    initialState,
    reducers: {
        setFruit: (state, action) => {
            state.fruitname = action.payload;
        }
    }
})

export const selectFruit = (state) => state.fruit.fruitname;
export const { setFruit } = fruitSlice.actions;
export default fruitSlice.reducer;

Component 1: features/fruits/SimpleFruit.js

import React from 'react';
import { selectFruit, setFruit } from './fruitSlice';
//import { useDispatch } from 'react-redux'; //PREVIOUS
import { useSelector, useDispatch } from 'react-redux'; //NEW

export function SimpleFruit(props) {
    // Parameters
    const {seller} = props;
    // Store state
    //const fruit = selectFruit(); //PREVIOUS
    const fruit = useSelector(selectFruit); //NEW
    const dispatch = useDispatch();
    // Callbacks (NEW)
    const handleChange = (e) => {
        dispatch(setFruit(e.target.value)); // needed for setting value
    }
    // Render
    return(
        <div>
            <p>SIMPLE FRUIT by <b>{seller}</b></p>
            <label htmlFor="fname">Fruit Name:</label>
            <input
              type="text"
              id="fname"
              name="fname"
              value={fruit}
              onChange={handleChange}
            />
        </div>
    );
}

Component 2: features/fruits/FruitLabel.js

import React from 'react';
import { selectFruit } from './fruitSlice';
import { useSelector } from 'react-redux'; //NEW

export function FruitLabel(props) {
    // Store state
    //const fruit = selectFruit(); //PREVIOUS
    const fruit = useSelector(selectFruit); //NEW
    // Render
    return(
        <h1>FRUIT IS {fruit}</h1>
    );
}

and finally, the main app: App.js:

import React from 'react';
import './App.css';
// Custom
import { SimpleFruit } from './features/fruits/SimpleFruit';
import { FruitLabel } from './features/fruits/FruitLabel';

function App() {
  return (
    <div className="App">
      <SimpleFruit seller="John Doe" />
      <FruitLabel />
    </div>
  );
}

export default App;

CodePudding user response:

You need to pass selectFruit to useSelector:

import { useSelector } from 'react-redux';
// ...

export function SimpleFruit(props) {
  const fruit = useSelector(selectFruit);
  // ...
}
  • Related