javascript - React redux state is undefined on first render despite of initlizedState - Stack Overflow

Redux state is undefined in first render and I returned the initilizedState = {} in my reducerstore.js

Redux state is undefined in first render and I returned the initilizedState = {} in my reducer

store.js

const store = createStore(
    rootReducer,

    pose(
        applyMiddleware(thunk),
        window.devToolsExtension ? window.devToolsExtension() : (f) => f
    )
)

export default store

rootReducer.js

const rootReducer = bineReducers({
    search: searchReducer,
    product: productReducer,
})

export default rootReducer

reducer.js

const initialState = {}
const productReducer = (state = initialState, action) => {
    const { type, payload } = action
    switch (type) {
        case PRODUCTS_ALL:
            console.log('reducer')
            return { ...state, items: payload }
        default:
            return state
    }
}

export default productReducer

action.js

const products = axios.create({
    baseURL: 'http://localhost:8001/api/products',
})
export const allProducts = () => async (dispatch) => {
    console.log('fetching')
    await products.get('/').then((res) => {
        dispatch({
            type: PRODUCTS_ALL,
            payload: res.data,
        })
    })
}

And although I used connect() in my feed container

Feed.js

function Feed({ allProducts, product }) {
    const [productItems, setProductItems] = useState()
    const [loading, setLoading] = useState(false)

    React.useEffect(() => {
        allProducts()
        console.log(product)
    }, [])

    return (
        
                            
            <div className='feed__content'>
                {loading ? (
                    <Loader
                        type='Oval'
                        color='#212121'
                        height={100}
                        width={100}
                    />
                ) : (
                    <div className='feed__products'>
                        <div className='feed__productsList'>
                             {product.map((product) => {
                                return (
                                    <Product
                                        name={product.name}
                                        image={product.image}
                                        price={product.price}
                                    />
                                )
                            })} 
                        </div>
                        
                    </div>
                )}

        </div>
    )
}

const mapStateToProps = (state) => ({
    product: state.product.items,
})
const mapDispatchToProps = (dispatch) => {
    return {
        allProducts: () => dispatch(allProducts()),
    }
}
export default connect(mapStateToProps, mapDispatchToProps)(Feed)

if you look at the data on the console you will see undefined but if I add a useEffect dependency it will create a loop , and the first of them is undefined and the rest are the data that I want. because of this problem when I want to render products with map , it throws an error that said can't map undefiend .

How can I solve this problem

Redux state is undefined in first render and I returned the initilizedState = {} in my reducer

store.js

const store = createStore(
    rootReducer,

    pose(
        applyMiddleware(thunk),
        window.devToolsExtension ? window.devToolsExtension() : (f) => f
    )
)

export default store

rootReducer.js

const rootReducer = bineReducers({
    search: searchReducer,
    product: productReducer,
})

export default rootReducer

reducer.js

const initialState = {}
const productReducer = (state = initialState, action) => {
    const { type, payload } = action
    switch (type) {
        case PRODUCTS_ALL:
            console.log('reducer')
            return { ...state, items: payload }
        default:
            return state
    }
}

export default productReducer

action.js

const products = axios.create({
    baseURL: 'http://localhost:8001/api/products',
})
export const allProducts = () => async (dispatch) => {
    console.log('fetching')
    await products.get('/').then((res) => {
        dispatch({
            type: PRODUCTS_ALL,
            payload: res.data,
        })
    })
}

And although I used connect() in my feed container

Feed.js

function Feed({ allProducts, product }) {
    const [productItems, setProductItems] = useState()
    const [loading, setLoading] = useState(false)

    React.useEffect(() => {
        allProducts()
        console.log(product)
    }, [])

    return (
        
                            
            <div className='feed__content'>
                {loading ? (
                    <Loader
                        type='Oval'
                        color='#212121'
                        height={100}
                        width={100}
                    />
                ) : (
                    <div className='feed__products'>
                        <div className='feed__productsList'>
                             {product.map((product) => {
                                return (
                                    <Product
                                        name={product.name}
                                        image={product.image}
                                        price={product.price}
                                    />
                                )
                            })} 
                        </div>
                        
                    </div>
                )}

        </div>
    )
}

const mapStateToProps = (state) => ({
    product: state.product.items,
})
const mapDispatchToProps = (dispatch) => {
    return {
        allProducts: () => dispatch(allProducts()),
    }
}
export default connect(mapStateToProps, mapDispatchToProps)(Feed)

if you look at the data on the console you will see undefined but if I add a useEffect dependency it will create a loop , and the first of them is undefined and the rest are the data that I want. because of this problem when I want to render products with map , it throws an error that said can't map undefiend .

How can I solve this problem

Share Improve this question edited Sep 15, 2021 at 16:17 General Grievance 5,04338 gold badges37 silver badges56 bronze badges asked Sep 15, 2021 at 7:59 siamak alipoursiamak alipour 632 silver badges8 bronze badges 5
  • Did you actually define initial state? (state = initialState, action) – Nectos Commented Sep 15, 2021 at 8:03
  • @Nectos Yes i added initialState – siamak alipour Commented Sep 15, 2021 at 8:07
  • Can you show us how you're initializing the redux store? What does your createStore function invocation look like? Did you add a preloaded state? – Andrew Commented Sep 15, 2021 at 8:09
  • @Andrew i added my store.js file sir what should i do – siamak alipour Commented Sep 15, 2021 at 8:15
  • Ok, if I understood it right, the first render actually occurs faster than a state change, resulting in undefined part, so on second render it will populate with data (also product?.map can help). You can add guard clause to prevent render while there is no data. Because it is in reducer store, you actually can use useSelector. Also I don't see where loading is being set to true. – Nectos Commented Sep 15, 2021 at 8:17
Add a ment  | 

4 Answers 4

Reset to default 2

Joel Jaimon code worked well .

and in my code I added

const initialState = {
  items: []
}

according to @Andrew and product?.map so my code works well now.

In Feed.js, you aren't getting the entire slice of state. You are trying to access the key item inside.

const mapStateToProps = (state) => ({
    product: state.product.items,
})

Change your initialState to include that key and your code should be fine

const initialState = {
  items: []
}

A/c to your code you're trying to make an async action in redux. You should use redux-saga or redux-thunk for this.

But you can achieve your output in the following way, without using redux-saga or thunk.

Modify your code in the following way:

Feed.js

function Feed({ allProducts, product }) {
  // Set loading to true inititally
  const [loading, setLoading] = useState(true);

  React.useEffect(() => {
    // Make your api call here once its plete and you get a res, 
    // dispatch the referred action with response as payload.
    (async () => {
        const products = axios.create({
            baseURL: "http://localhost:8001/api/products",
          });
        const {data} = await products.get("/");
        allProducts(data);
    })()
  // This call is only made when you load it for the first time, if it 
  // depends 
  // on something add that dependencies in the dependency array of // 
  // useEffect.
  }, []);

  // once store is updated with the passed payload. Set loading to 
  // false.
  React.useEffect(() => {
    if(product){
        setLoading(false);
    }
  }, [product])

  return (
    <div className="feed__content">
      {loading ? (
        <Loader type="Oval" color="#212121" height={100} width={100} />
      ) : (
        <div className="feed__products">
          <div className="feed__productsList">
            {product.map((product) => {
              return (
                <Product
                  name={product.name}
                  image={product.image}
                  price={product.price}
                />
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}


const mapStateToProps = ({product}) => ({
  product: product?.items,
});

// here we have a payload to pass
const mapDispatchToProps = (dispatch) => {
  return {
    allProducts: (payload) => dispatch(allProducts(payload)),
  };
};
export default connect(mapStateToProps, mapDispatchToProps)(Feed);

Action

export const allProducts = (payload) => ({   
      type: "PRODUCTS_ALL",
      payload,
});

Reducer

const productReducer = (state = initialState, action) => {
    const { type, payload } = action
    switch (type) {
        case "PRODUCTS_ALL":
            return { ...state, items: payload }
        default:
            return state
    }
}

export default productReducer

Problem statement: I would be giving you three really best methods, in order to solve it, the problem appears when redux is transferring states to the ponents, so it seems that the render is faster than the response of props to the ponent.

So, when you have props undefined by their value your application crashes.


note: I will be taking a general example and will show you how to avoid this error.

For example, I have a ponent in which I want to render the data from the redux response (with mapPropsToState), what I need to do is only to check it for undefined and then if it is undefined we need to use the conditional (ternary) operator for if and else statements.

//suppose you will get an address object from api ,which will contain city ,area ,street ,pin code etc
// address={} intially address is a blank object
render(){
    return(
        (typeof address.area!='undefined')?
        <div>
        <div>{address.city}</div>
        <div>{address.street}</div>
        <div>{address.pin_code}</div>
        <div>{address.area}</div>
        </div>
        :<div>loading....</div>
    )
}

And another way is to simply use the package of loadash in loadash you can achieve the same by calling the function "isUndefined" you can also use it in the inputFields likewise

<FloatingLabel  label="Username">
                  <Form.Control
                    type="input"
                    placeholder=" "
                    name="username"
                    value={props.username}
                    defaultValue={_.isUndefined(props.userEditResponse)?'':props.userEditResponse.username}

                    required
                  onChange={(e)=>onInputchange(e)}
                 

                  />
                </FloatingLabel>
   //note: you can also use (typeof props.userEditResponse!='undefined')?'do somthing':'leave it'

loadash installation:

npm i lodash then in your ponent import the the below line and then you can use it, the way i used in the above example.

import _ from 'lodash'

note: the answer was just to give you an idea and this was really a panic problem that is why I shared it with you guys, it might help many of you, you can use a similar way in different situations. thanks!

furtherMore your can work with ?.:

The ?. operator is like the . chaining operator, except that instead of causing an error if a reference is nullish (null or undefined), the expression short-circuits with a return value of undefined. When used with function calls, it returns undefined if the given function does not exist.

This results in shorter and simpler expressions when accessing chained properties when the possibility exists that a reference may be missing. It can also be helpful while exploring the content of an object when there's no known guarantee as to which properties are required.

      { props.rolesListSuccessResponse?.permissions.map((list,index) => (
 
    <div  className="mb-3 col-md-3" key={index}>
      <Form.Check 
        type={'checkbox'}
        id={list.name}
        label={list.name.charAt(0).toUpperCase()+list.name.slice(1)}
      />

    </div>
   
  ))}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745438606a4627725.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信