Ошибка типа: products.map не является функцией. Скорее всего, проблемы в redux

#javascript #node.js #reactjs #redux #mern

Вопрос:

Как решить эту проблему? Я прикрепил все соответствующие фрагменты кода здесь. Когда я пытаюсь отобразить продукты на главном экране, я получаю эту ошибку, когда я открываю этот проект, он показывает загрузку в течение нескольких секунд, а затем показывает эту ошибку. Что нужно сделать для исправления этой ошибки?

 import React, { useEffect} from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Row, Col } from 'react-bootstrap'
import Product from '../components/Product'
import { listProducts } from '../actions/productActions.js'
import Message from '../components/Message'
import Loader from '../components/Loader'

const HomeScreen = () => {
    const dispatch = useDispatch()

  const productList = useSelector((state) => state.productList);
  const { loading, error, products} = productList;

  useEffect(() => {
    dispatch(listProducts())
  }, [dispatch])
    return (
        <>
            <h1>All Products</h1>
            {loading ? (
                <Loader />
            ) : error ? (
                <Message variant='danger'>{error}</ Message>
            ) : (
                <Row>
                {products.map((product) => (
                    <Col sm={12} md={6} lg={4} xl={3} key={product._id}>
                        <Product product={product} />
                    </Col>
                ))}
            </Row>
            )}    
        </>
    )
}

export default HomeScreen
 

А вот страница productAction в redux

 import {PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS, PRODUCT_LIST_FAIL, 
    PRODUCT_DETAILS_REQUEST, PRODUCT_DETAILS_SUCCESS, PRODUCT_DETAILS_FAIL} from '../constants/productConstants'
import axios from 'axios'

export const listProducts = () => async (dispatch) => {
    try {
        dispatch({ type: PRODUCT_LIST_REQUEST })

        const {data} = await axios.get('/api/products')

        dispatch({
            type: PRODUCT_LIST_SUCCESS,
            payload: data
        })
    } catch (error) {
        dispatch({
            type: PRODUCT_LIST_FAIL,
            payload:
                error.response amp;amp; error.response.data.message
                    ? error.response.data.message
                    : error.message
        })

    }
}

export const listProductDetails = (id) => async (dispatch) => {
    try {
      dispatch({ type: PRODUCT_DETAILS_REQUEST })
  
      const { data } = await axios.get(`/api/products/${id}`)
  
      dispatch({
        type: PRODUCT_DETAILS_SUCCESS,
        payload: data,
      })
    } catch (error) {
      dispatch({
        type: PRODUCT_DETAILS_FAIL,
        payload:
          error.response amp;amp; error.response.data.message
            ? error.response.data.message
            : error.message,
      })
    }
  }
 

Страница производителей продукции:

 import {PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS, PRODUCT_LIST_FAIL,
    PRODUCT_DETAILS_REQUEST, PRODUCT_DETAILS_SUCCESS, PRODUCT_DETAILS_FAIL} from '../constants/productConstants'

export const productListReducer = (state = { products: []}, action ) => {
    switch( action.type ) {
        case PRODUCT_LIST_REQUEST:
            return { loading: true, products: []}
        case PRODUCT_LIST_SUCCESS:
            return { loading: false, products: action.payload}
        case PRODUCT_LIST_FAIL:
            return { loading: false, error: action.payload}
        default:
            return state
    }
}

export const productDetailsReducer = (
    state = { product: { reviews: [] } },
    action
  ) => {
    switch (action.type) {
      case PRODUCT_DETAILS_REQUEST:
        return { loading: true, ...state }
      case PRODUCT_DETAILS_SUCCESS:
        return { loading: false, product: action.payload }
      case PRODUCT_DETAILS_FAIL:
        return { loading: false, error: action.payload }
      default:
        return state
    }
  }
 

Комментарии:

1. Вы проверили данные ответа? Это массив ?

2. Можете ли вы показать часть редуктора?

3. @AbinThaha это добавлено сейчас.

4. @AzizulTareq отладьте в точке состояния и проверьте, что вы получаете в состоянии, я думаю, productList здесь проблема в том, что ключ

Ответ №1:

  1. Сначала посмотрите, правильно ли работает ваш API.
  2. Если он работает правильно, и даже тогда у вас возникает эта ошибка, то проблема заключается в том, как вы обновляете свой магазин redux. Здесь продукты-это элемент из списка продуктов. Вы меняете свойство объекта, но сам объект, похоже, не меняется с точки зрения реакции.

Проверьте свою логику редуктора, и если вы обновляете значение хранилища, сделайте это так

 initialState = { loading, error, products: [] }
......
......
  return {
     ...state,
     products: [...fetched products]
  }
 

эти 3 точки (…) гарантируют, что вы создадите новый объект. В redux вы всегда должны создавать новый объект, а не просто обновлять состояние.

  1. При использовании переменных всегда сначала убедитесь, что переменная и ее свойство, которые вы хотите использовать, существуют. В вашем случае вы напрямую используете products.map, и это нарушает интерфейс. Сначала проверьте, действительно ли продукты являются списком или нет, а затем используйте products.map. Таким образом, ваш интерфейс не сломается, даже если стоимость продуктов не определена.

Ответ №2:

Я решил эту проблему, добавив action.payload.products на страницу productReducers. Исправленный код находится здесь:

 export const productListReducer = (state = { products: []}, action ) => {
    switch( action.type ) {
        case PRODUCT_LIST_REQUEST:
            return { loading: true, products: []}
        case PRODUCT_LIST_SUCCESS:
            return { loading: false, products: action.payload.products}
        case PRODUCT_LIST_FAIL:
            return { loading: false, error: action.payload}
        default:
            return state
    }
}