首页 > 解决方案 > 未处理的拒绝(TypeError):无法在我的 cartActions.js 中读取未定义的属性(读取“数据”)

问题描述

我正在尝试在我的反应应用程序中使用 axios 进行身份验证时加载用户的购物车,但它返回一个错误,提示“无法读取未定义的属性(读取'数据')”。该错误突出显示了我的 cartAction.js:15 这是一个 .catch 方法,它返回错误响应数据和状态,但是当我 console.log 来自我的 axios.get( /api/cart/${id}) 的响应时,它在我的控制台中成功记录了响应,但它没有t 在我的反应应用程序中呈现。我认为问题出在我的 Cart.js 组件代码中,但我似乎无法纠正它。我的 cartAction.js getCart 常量中的 console.log(err) 打印“错误:Checkout(...): 没有从渲染返回。这通常意味着缺少返回语句。或者,不渲染任何内容,返回 null。 ”在我的控制台中

这是我的 cartAction.js 代码

> export const getCart = (id) => dispatch => {
>     dispatch(setCartLoading());
>     axios.get(`/api/cart/${id}`)
>          .then(res => dispatch({
>              type: GET_CART,
>              payload: res.data
>          })
>          )
>          .catch(err => { 
>              console.log(err) 
>              dispatch(returnErrors(err.response.data, err.response.status))}); }
> 
> export const addToCart = (id, productId, quantity) => dispatch => {
>     axios.post(`/api/cart/${id}`, {productId, quantity})
>          .then(res => dispatch({
>              type: ADD_TO_CART,
>              payload: res.data
>          }))
>          .catch(err => dispatch(returnErrors(err.response.data, err.response.status))); }
> 
> export const deleteFromCart = (userId, itemId) => dispatch => {
>     axios.delete(`/api/cart/${userId}/${itemId}`)
>     .then(res => dispatch({
>         type: DELETE_FROM_CART,
>         payload: res.data
>     }))
>     .catch(err => dispatch(returnErrors(err.response.data, err.response.status))); }
> 
> export const setCartLoading = () => {
>     return{
>         type: CART_LOADING
>     } }

这是我的组件/Cart.js 代码

class Cart extends Component{
     state = {
         loaded: false
     }

    static propTypes = {
        getCart: PropTypes.func.isRequired,
        isAuthenticated: PropTypes.bool,
        addToCart: PropTypes.func.isRequired,
        deleteFromCart: PropTypes.func.isRequired,
        user: PropTypes.object.isRequired,
        cart: PropTypes.object.isRequired,
        checkout: PropTypes.func.isRequired
    }


     getCartItems = async (id) => {
         await this.props.getCart(id);
         this.state.loaded = true;
     }

     onDeleteFromCart = (id, itemId) => {
         this.props.deleteFromCart(id, itemId);
     }

     render(){
         const user = this.props.user;
         if(this.props.isAuthenticated && !this.props.cart.loading && !this.state.loaded){
             this.getCartItems(user._id);
         }
         return(
             <div>
                 <AppNavbar/>
                 {this.props.isAuthenticated ?
                   <Fragment>
                       { this.props.cart.cart ? null :
                          <Alert className="text-center" color="info">Your cart is empty!</Alert>
                       }
                   </Fragment>
                   : <Alert className="text-center" color="danger">Login to View</Alert> 
                }

                {this.props.isAuthenticated && !this.props.cart.loading && this.state.loaded && this.props.cart.cart ?
                <Container>
                    <div className="row">
                        {this.props.cart.cart.items.map((item)=>(
                            <div className="col-md-4">
                                <Card>
                                    <CardBody>
                                        <CardTitle tag="h5">{item.name}</CardTitle>
                                        <CardSubtitle>NGN {item.price}</CardSubtitle>
                                        <CardText>Quantity - {item.quantity}</CardText>
                                        <Button color="danger" onClick={this.onDeleteFromCart.bind(this, user._id, item.productId)}>Delete</Button>
                                    </CardBody>
                                </Card>
                                <br/>
                            </div>
                        ))}
                        <div className="col-md-12">
                           <Card>
                               <CardBody>
                                   <CardTitle tag="h5">Total Cost = NGN. {this.props.cart.cart.bill}</CardTitle>
                                   <Checkout
                                   user={user._id}
                                   amount={this.props.cart.cart.bill}
                                   checkout={this.props.checkout}
                                   />
                               </CardBody>
                           </Card>
                        </div>
                    </div>
                </Container>
                : null
                }
             </div>
         );
     }
 }

 const mapStateToProps = (state) => ({
     cart: state.cart,
     isAuthenticated: state.auth.isAuthenticated,
     user: state.auth.user
 })

 export default connect(mapStateToProps, {getCart, deleteFromCart, checkout})(Cart);

这是我的 cartReducer.js 代码

const initialState = {
     cart: null,
     loading: false
 }

export default function cartReducer (state=initialState, action){
     switch(action.type){
         case GET_CART:
             return {
                 ...state,
                 cart: action.payload,
                 loading: false
             }

             case ADD_TO_CART:
                 return {
                     ...state,
                     cart: action.payload
                 }

            case DELETE_FROM_CART: 
                 return {
                     ...state,
                     cart: action.payload
                 }

            case CART_LOADING: 
                 return {
                     ...state,
                     loading: true
                 }

            default: 
            return state;
     }
 }

标签: javascriptnode.jsreactjsreduxaxios

解决方案


我想我现在看到了这个问题。render您正在从您的方法中发出副作用。render被认为是一个同步的纯函数。如果您需要获取数据,它应该在组件生命周期方法之一中,即componentDidMount和/或componentDidUpdate.

将“getCartItems”条件逻辑移动到实用程序函数中并从componentDidMount生命周期方法中调用。

fetchCartItems = () => {
  const { cart, isAuthenticated, user } = this.props;
  const { loaded } = this.state;

  if (isAuthenticated && !cart.loading && !loaded) {
    this.getCartItems(user._id);
  }
}

componentDidMount() {
  this.fetchCartItems();
}

...

render() {
  const { user } = this.props;

  return (
    <div>
      ...
    </div>
  );
}

如果在组件安装后您可能需要稍后再次获取购物车项目,例如,身份验证状态发生更改,请使用该componentDidUpdate方法。

componentDidUpdate() {
  this.fetchCartItems();
}

推荐阅读