Reputation: 83
My code is supposed to generate a popup of a product then add the product to the wishlist page. It gives an error that length is not defined, I think it because I misused hooks, I tried adding const [listVariations, setListVariations] = useState(0) in place of const [listVariations, setListVariations] = useState([]) but it still gives out same error can someone help me sort it out thanks in advance!
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;
Upvotes: 2
Views: 785
Reputation: 482
Basically, some of the content used with .length is undefined. The best way to learn which one is undefined
, is to use typeof
. You can use typeof variableName
to determine what is the type of the variable. If some of the types in the code are not List or Array, it will create an error. To debug, you can put alert("Type is not valid")
combined with methods to see. (Btw we are not having those data and determine what is errored.)
Upvotes: 1