I am receiving an error of "HomePage.jsx:16 Uncaught TypeError: elements.map is not a function" when trying to change the boxtitle for the array component. I have tried moving around functions and such but nothing seems to work.
I basically only want to change the title for the certain array object with the same boxid. Below is my code.
HomePage.jsx:
import react from 'react';
import { useEffect, useContext } from 'react';
import '../App.css';
import Todobox from './Todobox';
import { ElementContext } from '../ElementContext';
export default function HomePage(){
const { elements, setElements, newElement, elementId } = useContext(ElementContext);
return(
<div className='page-container'>
<div className='header'>
<a className='header-title'>Trello Clone!</a>
<a className='header-button' onClick={newElement}>Create a list</a>
</div>
<div className='element-field'>
{elements.map((element) => <Todobox key={element.boxid} boxid={element.boxid} boxtitle={element.boxtitle}/>)}
</div>
</div>
)
}
Todobox.jsx:
import React from 'react';
import Item from './Item';
import { useState, useContext } from 'react';
import '../App.css';
import { ElementContext } from '../ElementContext';
export default function Todobox({ boxtitle, boxid }){
const { elements, setElements } = useContext(ElementContext);
const [boxheader, setBoxHeader] = useState();
const handleSubmit = (e) => {
const object = elements.find(obj => {
if (obj.boxid === boxid){
setBoxHeader(e.target.value)
return obj
}})
setElements({...object, boxtitle: boxheader})
}
const handleKeydown = (e) => {
if(e.keyCode == 13 && e.shiftKey == false){
e.preventDefault();
handleSubmit(e)
}
}
return(
<div className='element-box'>
<textarea className='element-title-input' placeholder={boxtitle} onKeyDown={handleKeydown}/>
<Item />
<textarea
className='element-input'
type='text'
placeholder={`Add item... ${boxid}`}
onClick={() => {console.log(boxid)}}
/>
</div>
)
}
ElementContext.js:
import React, { createContext, useState } from 'react';
import Todobox from './components/Todobox';
export const ElementContext = createContext();
export const ElementContextProvider = ({children}) => {
const [elements, setElements] = useState([]);
const [elementId, setElementId] = useState(1);
const [title, setTitle] = useState('Add title...');
const [refDict, setRefDict] = useState({});
const newElementId = (elements) =>{
setElementId(elementId 1);
console.log(elementId)
}
const newElement = () => {
newElementId();
if (!refDict[elementId]) {
setElements(prev => [...prev, { boxtitle: title, boxid: elementId }]);
setRefDict((prev) => ({...prev, [elementId]: true}));
}
console.log(elements);
};
const value = {
elements,
setElements,
newElement,
elementId,
};
return(
<ElementContext.Provider value={value}>
{children}
</ElementContext.Provider>
)
};
Any help is appreciated since I am new and still learning! :)
CodePudding user response:
Few points to handle
const newElement = () => {
newElementId(); // this wont update as react batches the state updates
// try using userRef for elementId
// create new element id here, and then set it
// const newId = elementId 1
// setElementId(newElementId)
if (!refDict[elementId]) {
setElements(prev => [...prev, { boxtitle: title, boxid: elementId }]);
setRefDict((prev) => ({...prev, [elementId]: true}));
}
console.log(elements);
};
on submit
const object = elements.find(obj => {
if (obj.boxid === boxid){
setBoxHeader(e.target.value) // wont update the as React will likely batch the state updates
return obj
}})
setElements({...object, boxtitle: boxheader}) // is this an array ?
instead try
const object = elements?.find(obj => obj.boxid === boxid)
if (object) {
setBoxHeader(e.target.value)
setElements([ object, { boxtitle: e.target.value, boxId: elementId } ]) // what is the structure of array elements
}
you will find the new React documentation about updating arrays useful
CodePudding user response:
use the optional operator ?
to make sure element has values
elements?.map(...