Home > Enterprise >  Error "elements.map is not a function" when trying to update array
Error "elements.map is not a function" when trying to update array

Time:11-10

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>
    )
};

Code Sandbox

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(...
  • Related