Hello. Help new in redux .

Why in this approach, the application breaks by displaying an error:

Cannot read property 'map' of undefined

 renderListHandler(){ return this.props.heroes.map(hero => { return ( <div key={hero.name}> <h4 onClick={this.props.onClickOneOfVariant}>{hero.name}</h4> </div> ) }) } renderImagesHandler(){ const heroes = this.props.heroes;//Добавляем переменную героев чтобы внизу использовать дважды const image = ~~(Math.random() * heroes.length); //Берем случайную картинку из героев return heroes[image].src; //Возвращаем картинку } render(){ const arr = this.renderListHandler(); //Возвращаем весь массив суда const shuffledArr = shuffle(arr); //Shuffle простой алгоритм чтобы перемещать массив ничего серьезного return ( <Container className="h-100"> <img src={this.renderImagesHandler()} alt="secret" /> //Показываем тут одну случайную картинку {shuffledArr} //Показываем тут перемещанный массив героев </Container> ) } 

This is part of Redux

 const mapStateToProps = state => { return { heroes: state.nameAndImage, ctr:state.counter }; } const mapDispatchToProps = dispatch => { return { onClickOneOfVariant:() => dispatch({type:"TRUEVARIANT"}) }; }; 

This is a reducer

 const initialState = { counter:0, nameAndImage:data } const rootReducer = (state = initialState, action) => { if(action.type === "TRUEVARIANT"){ return { counter:state.counter + 1, } } return state; } 

And data comes to him like this

 export const data = [{ src: Vers, name: "Captain Marvel" }, { src: Venom, name: "Venom" }, { src: Thanos, name: "Thanos" }] 

src inside data are pictures that I connected indicating the name to everyone

example: import Vers from "../assets/marvel/vers.jpg";

And used this Vers inside data

Without this onClickOneOfVariant event, everything works perfectly.

But if you add it, the page loads, but when you click on one of h4 displays an error

Cannot read property 'map' of undefined.

What am I doing wrong please tell me?

  • is this.props.heroes not an array? - Stranger in the Q
  • Because in heroes - lies undefined , hence the error. Write through defaultProps default value, an empty array will be normal. In the case of Ridax, initialize the variable in the props with an empty array initially. - Denis Bubnov
  • @DenisBubnov and can be more? - Demon __ ANT
  • @StrangerintheQ how to say this array which I myself created something like JSON only js.In one of the files I return an array that contains objects. And this file crammed into a reducer to work with it. - Demon __ ANT
  • In the case of Redux, you need to set the initial value, so to speak initialState in the reducer. Most examples will have this initial state. About defaultProps you can look here: Typechecking With PropTypes - Denis Bubnov 7:34 pm

2 answers 2

Pay attention to the code of your reducer:

 const initialState = { counter: 0, nameAndImage: data } const rootReducer = (state = initialState, action) => { if (action.type === "TRUEVARIANT") { return { counter: state.counter + 1, } } return state; } 

The initial state (when the action is not with the type TRUEVARIANT ) will be returned normal and complete, such as:

 counter: 0, nameAndImage: data 

However, in the case of the TRUEVARIANT type TRUEVARIANT result will be:

 counter: state.counter + 1 

That is, when accessing the nameAndImage nameAndImage inside the component will be undefined , because this variable is not initialized. Therefore it is necessary to make the following edit:

 return { ...state, counter: state.counter + 1 } 

The so-called spread syntax helps us copy the state object into the result (it copies its own enumerated properties of the state object into a new object.) And the line counter: state.counter + 1 overwrite the value from the past state with a new one.

  • one
    ahhh so here it is what was the problem .. Thank you so much for your help. - Demon __ ANT

To avoid such errors, I recommend using a combination of reducers in your roorReducer:

 import { combineReducers } from 'redux'; import { data } from 'somewhere-in-your-project'; const counterReducer = (state = 0, action) => { if (action.type === "TRUEVARIANT") { return state + 1; } return state; }; const nameAndImageReducer = (state = data, action) => { if (action.type === "TRUEVARIANT") { // возвращать данные для узла nameAndImage } return state; }; const rootReducer = combineReducers({ counter: counterReducer, nameAndImage: nameAndImageReducer, }); export default rootReducer; 

This way you work with each state node separately, minimizing the chances of affecting the neighboring nodes and avoiding errors.