我的代码应该生成一个产品的弹出窗口,然后将该产品添加到愿望列表页面。它给出了一个没有定义长度的错误,我认为这是因为我滥用了钩子,我尝试添加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;
基本上,与.length一起使用的一些内容是未定义的。学习哪一个是undefined
的最好方法是使用typeof
。您可以使用typeof variableName
来确定变量的类型。如果代码中的某些类型不是List或Array,则会产生错误。要调试,可以将alert("Type is not valid")
与方法结合起来查看。(顺便说一句,我们没有这些数据,并确定什么是错误的。(