【问题标题】:TypeError: Cannot read property 'length' of undefined in react jsTypeError:无法读取反应js中未定义的属性“长度”
【发布时间】:2020-11-28 14:44:26
【问题描述】:

我的代码应该生成产品的弹出窗口,然后将产品添加到愿望清单页面。它给出了一个未定义长度的错误,我认为这是因为我滥用了钩子,我尝试添加 const [listVariations, setListVariations] = useState(0) 代替 const [listVariations, setListVariations] = useState([]) 但它仍然给出同样的错误,谁能帮我解决一下提前谢谢!

import React, { Fragment, useContext, useState, useEffect} from 'react'
import './Sass/Index.scss'
import { WishListContext } from '../../contexts/WishListContext'
import { ProductContext } from '../../contexts/ProductContext'
import Popup from "reactjs-popup";

const Product = ({product, id, productIndex}) => {
    const{name, price, image, variation, option, unit, total} = product
    const {wishListState, wishListDispatch} = useContext(WishListContext)
    const {productState} = useContext(ProductContext)
    const [popupVariation, setPopupVariation] = useState(false)
    const [popupOption, setPopupOption] = useState(false)
    const [listVariations, setListVariations] = useState([])
    const [listOptions, setListOptions] = useState([])
    const [selectedOption, setSelectedOption] = useState({})
    const [updateToggle, setUpdateToggle] = useState(false)
   

    useEffect(()=> {
        generatePopupVariation()
        generatePopupOptions()
    }, [productState])

    const updateLocalStorage = (products) => {
        if (products.length > 0) {
            wishListDispatch({
                type:"REPLACE_WISH",
                payload: products.map(item => item)
            })
        } 
    }

    const generatePopupOptions = () => {
        const products = productState.products
        if (products.length > 0) {
            const finedProduct = products.find(item => item.id === id)
            const priceOptions = finedProduct?.data.priceOptions
            setListOptions(priceOptions && priceOptions[0].options) 
        }
    }

    const generatePopupOptionContent= () => {
        if ( listOptions.length > 0 ) {
           const filtered = listOptions.filter(item => item.is_available !== 'No')
           return filtered.map((item, index) => <li key={index}><span>{item.option}</span><span>Price: {item.price}</span><div className="btn btn-primary" onClick={() => changeOption(index, item.option, item.price)} >Select</div></li>)
        }
    }

    const changeOption = (index, option, price) => {
        const action = {
            id,
            option,
            price
        }
        if (option) {
            wishListDispatch({
                type:'UPDATE_OPTION_WISH',
                action
            })
            updateLocalStorage(wishListState.products)
            modalOption('close')
        }  
    }

  
    const generatePopupVariation = () => {
        const products = productState.products
        if (products.length > 0) {
            const finedProduct = products.find(item => item.id === id)
            const priceOptions = finedProduct?.data.priceOptions
            setListVariations(priceOptions)
        }
    }

    const generatePopupVariationContent = () => {
     
     if ( listVariations.length > 0 ) {
      console.log(listVariations.length)
      return listVariations.map((item, index) => <li className="btn btn-primary" onClick={() => changeVariation(index, item.variation, item.options)} key={index}>{item.variation}</li>)
   }
    }

    const changeVariation = (index, variation, options) => {
        const action = {
            id,
            variation
        }
        if (variation) {
            wishListDispatch({
                type:'UPDATE_VARIATION_WISH',
                action
            })
            updateLocalStorage(wishListState.products)
            modalVariation('close')
        }  
    }
    
    const handleRemove = () => {
        if (wishListState) {
            if( wishListState.products.length > 0) {
                wishListDispatch({
                    type: 'REMOVE_WISH',
                    payload: productIndex
                })
            }
        }
    }
    const handleUnit = (control) => {
        if (wishListState) {
            if( wishListState.products.length > 0) {
                wishListDispatch({
                    type: 'ADD_UNIT_WISH',
                    payload: {index: productIndex, control:control}
                })
            }
        }
    }
    const modalVariation = action => {
        if (action === 'open') {
            setPopupVariation(true)
        } else if (action === 'close') {
            setPopupVariation(false)
        }
    }
    const modalOption = action => {
        if (action === 'open') {
            setPopupOption(true)
        } else if (action === 'close') {
            setPopupOption(false)
        }
    }

    return (
        <Fragment>
            <Popup
                open={popupVariation}
                closeOnDocumentClick
                onClose={()=> modalVariation('close')}
            >
                <div className="popup-content"> 
                    <ul>
                        {generatePopupVariationContent()}
                    </ul>
                    <span onClick={() => modalVariation('close')}>X</span>
                </div>
            </Popup>
            <Popup
                open={popupOption}
                closeOnDocumentClick
                onClose={()=> modalOption('close')}
            >
                <div className="popup-content"> 
                    <ul>
                        {generatePopupOptionContent()}
                    </ul>
                    <span onClick={() => modalOption('close')}>X</span>
                </div>
            </Popup>
                <div className="card">
                    <div className="card-wrapper">
                        <div className="left">
                            <img className="card-img" src={ image } alt={ name } />
                        </div>
                        <div className="right">
                            <div className="card-remove" onClick={handleRemove}>
                                <i className="times" name="close"></i>
                            </div>
                            <h4 className="card-title">{ name }</h4>
                            { variation && <p className="card-variation"><span>Variation:</span><span>{variation} <span onClick={()=> modalVariation('open')} className="change-variation"><ion-icon name="create"></ion-icon></span></span> </p>}
                            { option && <p className="card-option"><span>Option:</span><span> { option }  <span onClick={()=> modalOption('open')} className="change-option"><ion-icon name="create"></ion-icon></span></span></p>}
                            <div className="card-unit"><span>Qty:</span>
                                <div className="card-units-wrapper">
                                    <i className="plus" name="add" onClick={() => handleUnit('+')}></i>
                                    <div className="card-units">{unit}</div>
                                    <i className="minus" name="remove" onClick={() => handleUnit('-')}></i>
                                </div>
                            </div>
                            <p className="card-price"><span>Price:</span><span> {price} </span></p>
                            <p className="card-total"><span>Total:</span> <span>{total} </span></p>
                        </div>
                    </div>
                </div>
        </Fragment>
    )
}

export default Product

ProductContext.js

import React, { createContext, useReducer } from 'react'
import ProductReducer from '../reducers/ProductReducer'

export const ProductContext = createContext()

const initState = {
    products: []
}

const ProductProvider = props => {
    const [ productState, productDispatch ] = useReducer(ProductReducer, initState)
    const value = {productState, productDispatch}
    return (
        <ProductContext.Provider value={value}>
            {props.children}
        </ProductContext.Provider>
    )
}

export default ProductProvider

ProductReducer.js

const ProductReducer = (state, action) => {
    switch (action.type) {
        case "LOAD_PRODUCTS":
            return {...state, products: [...action.payload]}
        case "ADD_PRODUCT":
            return {...state, products: [...state.products, action.payload]}
        default:
            return state
    }
}
export default ProductReducer;

WishlistContext.js

import React, { createContext, useReducer } from 'react'
import WishListReducer from '../reducers/WishListReducer'
export const WishListContext = createContext()

const initState = {
    products: [],
    select_variation:null
}
const WishListProvider = props => {
    const [ wishListState, wishListDispatch ] = useReducer(WishListReducer, initState)
    const value = {wishListState, wishListDispatch }
    return (
        <WishListContext.Provider value={value}>
            {props.children}
        </WishListContext.Provider>
    )
}

export default WishListProvider

WishlistReducer.js

const WishListReducer = (state, action) => {
    switch (action.type) {
        case "ADD_WISH":
            return addWish(state, action)
        case "REPLACE_WISH":
            return replaceWish(state, action)
        case "REMOVE_WISH":
            return removeWish(state, action)
        case "ADD_UNIT_WISH":
            return unitWish(state, action)
        case "UPDATE_VARIATION_WISH":
            return updateVariation(state, action)
        case "UPDATE_OPTION_WISH":
            return updateOption(state, action)
        default:
            return state
    }
}

const addWish = (state, action) => {
    localStorage.setItem('wish-list', JSON.stringify({...state, products: [...state.products, action.payload] }))
    return {...state, products: [...state.products, action.payload] }
}

const replaceWish = (state, action) => {
    localStorage.setItem('wish-list', JSON.stringify({...state, products: [...action.payload] }))
    return {...state, products: [...action.payload] }
}

const removeWish = (state, action) => {
    const copyState = {...state }
    copyState.products.splice(action.payload, 1);
    localStorage.setItem('wish-list', JSON.stringify({...state, products: [...copyState.products] }))
    return {...state, products: [...copyState.products] }
}

const unitWish = (state, action) => {
    const copyState = {...state }
    const index = copyState.products[action.payload.index]
    const ctrl = action.payload.control
    const unit = index.unit
    const price = index.price
    if (ctrl == "+") {
        index.unit = Number(unit) + 1
        index.total = Number(price) * (Number(unit) + 1)
    }
    if (ctrl == "-") {
        if (Number(unit) <= 1) {
            index.unit = 1
        } else {
            index.unit = Number(unit) - 1
            index.total = Number(price) * (Number(unit) - 1)
        }
    }
    localStorage.setItem('wish-list', JSON.stringify({...state, products: [...copyState.products] }))
    return {...state, products: [...copyState.products] }
}

const updateVariation = (state, action) => {
    const id = action.action.id
    const variation = action.action.variation
    const copyState = {...state }
    const product = copyState.products.find(item => item.id == id)
    product.variation = variation
    return {...state, products: [...copyState.products] }
}

const updateOption = (state, action) => {
    const id = action.action.id
    const option = action.action.option
    const price = action.action.price
    const copyState = {...state }
    const product = copyState.products.find(item => item.id === id)
    product.option = option
    product.price = price
    product.total = product.unit * price
    return {...state, products: [...copyState.products] }
}


export default WishListReducer;

【问题讨论】:

  • 您能指定代码中的哪一行抛出错误吗?您有 8 个 .length 实例,更具体会有所帮助。
  • 如果您从lengthproducts 属性中检查length,您有两个可能触发此问题的上下文
  • 向我们展示您的productState.products 结构。
  • @AntonioErdeljac listVariations.length > 0 ,这个

标签: reactjs react-redux


【解决方案1】:

基本上,与 .length 一起使用的一些内容是未定义的。了解哪个是undefined 的最佳方法是使用typeof。您可以使用typeof variableName 来确定变量的类型。如果代码中的某些类型不是 List 或 Array,则会产生错误。要调试,可以把alert("Type is not valid")结合方法看。 (顺便说一句,我们没有这些数据并确定出了什么问题。)

【讨论】:

  • 我已经这样做了,变量类型是一个对象,然后正如我之前提到的,我尝试替换 const [listVariations, setListVariations] = useState(0) 代替 const [listVariations, setListVariations] = useState ([]) as .length 不能应用于对象
  • 你可以试试 useState(new Array())
猜你喜欢
  • 2020-07-27
  • 2019-12-28
  • 2021-09-18
  • 1970-01-01
  • 2020-06-03
  • 2020-06-12
  • 1970-01-01
  • 2021-02-01
相关资源
最近更新 更多