1

我正在尝试使用和从Django REST API服务器加载数据,我在其他屏幕(如产品、博客帖子)中使用的类似方法,它们工作正常,现在我需要从中加载另一个模型,但我不确定为什么会出现这个错误...... reduxaxiosapiTypeError: Cannot destructure property 'error' of 'panelMembersList' as it is undefined.

有问题的代码 panelMembersList.js

import { useState, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Row, Col, Card, Container, Button} from 'react-bootstrap'
// import PanelMember from '../components/PanelMember'
import { Link } from 'react-router-dom'
import Rating from '../components/Rating'
import Loader from '../components/Loader'
import Message from '../components/Message'
import Paginate from '../components/Paginate'
import { listPanelMembers } from '../actions/panelMemberActions'

function PanelListScreen({history}) {
    const dispatch = useDispatch()
    const panelMembersList = useSelector(state => state.panelMembersList)
    const {error, loading, allPanelMembers, page, pages } = panelMembersList

    let keyword = history.location.search
    useEffect(() => {
        dispatch(listPanelMembers(keyword))

    }, [dispatch, keyword])

    return (
        <div>
            <h3>Our Panel Members</h3>
            {loading ? <Loader />
                : error ? <Message variant='danger'>{error}</Message>
                    :
                    <div>
                        <Container variant='success'>
                        <Row>
                                {allPanelMembers.map(allPanelMembers => (
                                    <Col key={allPanelMembers._id} sm={12} md={6} lg={4} xl={3}>
                                        <Card style={{minWidth:'auto', maxWidth:'auto'}}   >
                                        
                                        </Card>

                                        <Card style={{ width: '18rem' ,  height: '30rem'}} className= "card border-success mb-2 my-0 p-2 rounded">
                                        <Card.Header>Joined Date : {allPanelMembers.createdAt}</Card.Header>
                                        <Link to={`/panel/${allPanelMembers._id}`}>
                                        <Card.Img className='mb-0 my-0 p-0' src={allPanelMembers.image} />
                                        </Link>
                                        <Card.Body>
                                            <Link to={`/panel/${allPanelMembers._id}`}>
                                                <Card.Title as="h5"><strong>{allPanelMembers.name}</strong></Card.Title>
                                            </Link>
                                            <Card.Text as="div">
                                            <div className="my-0">
                                                <Rating value={allPanelMembers.rating} text={`${allPanelMembers.numReviews} reviews`} color={'#f8e825'} />
                                            </div>
                                        </Card.Text>
                                        <Link to={`/panel/${allPanelMembers._id}`}><Button variant="btn btn-outline-success">
                                        Read More </Button></Link>
                                        </Card.Body>
                                        </Card>

                                    </Col>
                                ))}
                        </Row>
                        <Paginate page={page} pages={pages} keyword={keyword} />
                        </Container>
                    </div>
            }
        </div>
    )
}

export default PanelListScreen

当我加载此屏幕时,我收到以下错误

 12 | function PanelListScreen({history}) {
  13 |     const dispatch = useDispatch()
  14 |     const panelMembersList = useSelector(state => state.panelMembersList)
> 15 |     const {error, loading, allPanelMembers, page, pages } = panelMembersList
  16 | 
  17 |     let keyword = history.location.search
  18 |     useEffect(() => {

指示错误未定义,你能帮忙解决这个问题吗?

store.js

import { createStore, combineReducers, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import {
    productListReducer,
    productDetailsReducer,
    productDeleteReducer,
    productCreateReducer,
    productUpdateReducer,
    productReviewCreateReducer,
    productTopRatedReducer,
} from './reducers/productReducers'

import {
    panelMemberListReducer,
    panelMemberDetailsReducer,
    panelMemberReviewCreateReducer,

} from './reducers/panelMemberReducers'


import {
    blogPostListReducer,
    blogPostDetailsReducer,
    blogPostReviewCreateReducer,
} from './reducers/blogReducers'

import { cartReducer } from './reducers/cartReducers'

import {
    userLoginReducer,
    userRegisterReducer,
    userDetailsReducer,
    userUpdateProfileReducer,
    userListReducer,
    userDeleteReducer,
    userUpdateReducer,
} from './reducers/userReducers'

import {
    orderCreateReducer,
    orderDetailsReducer,
    orderPayReducer,
    orderListMyReducer,
    orderListReducer,
    orderDeliverReducer,
} from './reducers/orderReducers'

import  {
    messageListReducer,
    messageDetailsReducer,
}  from './reducers/messageReducers'


const reducer = combineReducers({
    productList: productListReducer,
    productDetails: productDetailsReducer,
    productDelete: productDeleteReducer,
    productCreate: productCreateReducer,
    productUpdate: productUpdateReducer,
    productReviewCreate: productReviewCreateReducer,
    productTopRated: productTopRatedReducer,

    panelMemberList: panelMemberListReducer,
    panelMemberDetail: panelMemberDetailsReducer,
    panelMemberReviewCreate: panelMemberReviewCreateReducer,

    cart: cartReducer,
    userLogin: userLoginReducer,
    userRegister: userRegisterReducer,
    userDetails: userDetailsReducer,
    userUpdateProfile: userUpdateProfileReducer,
    userList: userListReducer,
    userDelete: userDeleteReducer,
    userUpdate: userUpdateReducer,

    orderCreate: orderCreateReducer,
    orderDetails: orderDetailsReducer,
    orderPay: orderPayReducer,
    orderListMy: orderListMyReducer,
    orderList: orderListReducer,
    orderDeliver: orderDeliverReducer,

    blogPostList: blogPostListReducer,
    blogPostDetails: blogPostDetailsReducer,
    blogPostReviewCreate: blogPostReviewCreateReducer,

    listMessages: messageListReducer,
})


const cartItemsFromStorage = localStorage.getItem('cartItems') ?
    JSON.parse(localStorage.getItem('cartItems')) : []

const userInfoFromStorage = localStorage.getItem('userInfo') ?
    JSON.parse(localStorage.getItem('userInfo')) : null


const shippingAddressFromStorage = localStorage.getItem('shippingAddress') ?
    JSON.parse(localStorage.getItem('shippingAddress')) : {}


const initialState = {
    cart: {
        cartItems: cartItemsFromStorage,
        shippingAddress: shippingAddressFromStorage,
    },
    userLogin: { userInfo: userInfoFromStorage },
}

const middleware = [thunk]

const store = createStore(reducer, initialState,
    composeWithDevTools(applyMiddleware(...middleware)))

export default store

行动

export const listPanelMembers = (keyword = '') => async (dispatch) => {
    try {
        dispatch({ type: PANEL_LIST_REQUEST })

        const { data } = await axios.get(`/api/panel${keyword}`)

        dispatch({
            type: PANEL_LIST_SUCCESS,
            payload: data
        })

    } catch (error) {
        dispatch({
            type: PANEL_LIST_FAIL,
            payload: error.response && error.response.data.detail
                ? error.response.data.detail
                : error.message,
        })
    }
}

减速器

export const panelMemberListReducer = (state = { allPanelMembers: [] }, action) => {
    switch (action.type) {
        case PANEL_LIST_REQUEST:
            return { loading: true, allPanelMembers: [] }

        case PANEL_LIST_SUCCESS:
            return {
                loading: false,
                allPanelMembers: action.payload.allPanelMembers,
                page: action.payload.page,
                pages: action.payload.pages
            }

        case PANEL_LIST_FAIL:
            return { loading: false, error: action.payload }

        default:
            return state
    }
}

api端点 http://localhost:8000/api/panel/

4

2 回答 2

1

在 useSelector 钩子返回数据之前访问该值,或者在您的 redux 存储中未定义主对象。你可以做的是检查这个对象是否存在然后解构

例子:

const panelMembersList = useSelector(state => state.panelMembersList)
const [panelData, updatePanelData] = useState({
  error: '',
  loading: false, 
  allPanelMembers: [], 
  page: 0, 
  pages: 0
});

useEffect(() => {
  if(panelMembersList) updatePanelData(panelMembersList)

}, [panelMembersList])

或用默认数据填充您的 redux 存储中的该对象,以防止被识别为未定义

const initialState = {
  panelMembersList: {
   error: '',
   loading: false, 
   allPanelMembers: [], 
   page: 0, 
   pages: 0

  }
}

希望我的回答能帮助您解决问题

于 2021-06-25T12:00:11.817 回答
0

我想发布我做错了什么的答案,基本上是在我使用allPanelMembers端点访问数据之前,每次当我看到我的其他端点使用相同的方法工作正常但有一个区别我没有使用 camelCase 那里,这导致我改变了django侧面的变量,这可能会有所帮助。然后我改成allPanelMembers没有members驼峰箱。这解决了这个问题。曾经有人告诉我,如果我们在前端使用 react,则在后端使用 camelCase,但现在我知道这是不正确的。

正确代码:

#views.py
@api_view(['GET'])
def getAllPanelMember(request):
    query = request.query_params.get('keyword')
    if query == None:
        query = ''

    #originaly this variable was named allPanelMembers
    members = PanelMember.objects.filter(
        name__icontains=query).order_by('-createdAt') 

    page = request.query_params.get('page')
    paginator = Paginator(members, 8)

    try:
        members = paginator.page(page)
    except PageNotAnInteger:
        members = paginator.page(1)
    except EmptyPage:
        members = paginator.page(paginator.num_pages)

    if page == None:
        page = 1

    page = int(page)
    #print('Page:', page) If you want to see in termnial 
    serializer = PanelMemberSerializer(members, many=True)
    return Response({'members': serializer.data, 'page': page, 'pages': paginator.num_pages})

前端

import React, { useState, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Row, Col, Card, Image, ListGroup, Container } from 'react-bootstrap'
// import PanelMember from '../components/PanelMember'

import Loader from '../components/Loader'
import Message from '../components/Message'
import Paginate from '../components/Paginate'

import { panelMemberList } from '../actions/panelActions'


function PanelListScreen({ history }) {
    const dispatch = useDispatch()
    const panelList = useSelector(state => state.panelList)
    const { error, loading, members, page, pages } = panelList
    
    let keyword = history.location.search

    useEffect(() => {
        dispatch(panelMemberList(keyword))

    }, [dispatch, keyword])
    return (
        <div>
            <h1>Panel</h1>
            {loading ? <Loader /> : error ? <Message variant='danger'>{error}</Message> : <div>
                <Container>
                    <Row>
                        {
                            members.map(item=>(
                                <Col key={item._id} sm={12} md={6} lg={4} xl={3}>
                                    <Card.Header>By : {item.name}</Card.Header>
                                </Col>
                            ))
                        }</Row></Container></div>}
                <Paginate page={page} pages={pages} keyword={keyword} />
            </div>

    )
}

export default PanelListScreen
于 2021-06-27T05:05:32.917 回答