簡體   English   中英

盡管有 initlizedState,但 React redux 狀態在第一次渲染時未定義

[英]React redux state is undefined on first render despite of initlizedState

Redux 狀態在第一次渲染中未定義,我在減速器中返回了 initilizedState = {}

store.js

const store = createStore(
    rootReducer,

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

export default store

rootReducer.js

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

export default rootReducer

減速器.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

動作.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,
        })
    })
}

雖然我在我的提要容器中使用了 connect()

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)

如果您查看控制台上的數據,您將看到 undefined 但如果我添加一個 useEffect 依賴項,它將創建一個循環,其中第一個是未定義的,其余的是我想要的數據。 因為這個問題,當我想用​​ map 渲染產品時,它會拋出一個錯誤,說 can't map undefiend 。

我怎么解決這個問題

您嘗試在 redux 中執行異步操作的代碼的 A/c。 為此,您應該使用 redux-saga 或 redux-thunk。

但是您可以通過以下方式實現輸出,而無需使用 redux-saga 或 thunk。

通過以下方式修改您的代碼:

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 complete 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);

行動

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

減速器

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

導出默認 productReducer

Feed.js中,您沒有獲得完整的狀態片段。 您正試圖訪問里面的關鍵item

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

更改您的initialState以包含該鍵,您的代碼應該沒問題

const initialState = {
  items: []
}

Joel Jaimon代碼運行良好。

在我的代碼中我添加了

const initialState = {
  items: []
}

根據@Andrew和 product?.map 所以我的代碼現在運行良好。

問題陳述:我會給你三個非常好的方法,為了解決它,當 redux 將狀態轉移到組件時出現問題,所以看起來渲染比 props 對組件的響應更快。

因此,當您的 props 的值未定義時,您的應用程序就會崩潰


注意:我將舉一個一般性示例,並向您展示如何避免此錯誤。

例如,我有一個組件,我想在其中渲染來自 redux 響應的數據(使用 mapPropsToState),我需要做的只是檢查它是否未定義,然后如果它未定義,我們需要使用條件(三元) if 和 else 語句的運算符

//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>
    )
}

另一種方法是簡單地使用 loadash 中的 loadash 包,您可以通過調用函數“isUndefined”來實現相同的目的,您也可以在 inputFields 中同樣使用它

<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安裝:

npm i lodash 然后在您的組件中導入以下行,然后您可以使用它,就像我在上面的示例中使用的那樣。

import _ from 'lodash'

注意:答案只是給您一個想法,這確實是一個恐慌問題,這就是為什么我與你們分享它,它可能對你們中的許多人有所幫助,您可以在不同情況下使用類似的方式。 謝謝!

此外,您可以使用更多

這 ?。 運算符就像 . 鏈接運算符,除了如果引用為空(null 或未定義)時不會導致錯誤,表達式會短路並返回未定義的值。 與函數調用一起使用時,如果給定函數不存在,則返回 undefined。

當存在引用可能丟失的可能性時,當訪問鏈接屬性時,這會導致更短和更簡單的表達式。 當無法保證需要哪些屬性時,它在探索對象的內容時也很有幫助。

      { 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>
   
  ))}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM