I have created an array that gives a certain ID to each component every time it is added to the array. But now that the component is created, I want to be able to pull the data. Like the boxid or title when needed.
I currently am trying to make the value of <textarea />
in Todobox.jsx the unique boxid. But it does not seem to print a value.
Here is my code:
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(0);
const [refDict, setRefDict] = useState({});
const newElementId = (elements) =>{
setElementId(elementId 1);
console.log(elementId)
}
const newElement = () => {
newElementId();
if (!refDict[elementId]) { //so if nothing in "refDict" that means the elementId is unique
setElements(prev => [...prev, { title: 'Placeholder', boxid: elementId }]);
setRefDict((prev) => ({...prev, [elementId]: true}));
}
console.log(elements);
};
const value = {
elements,
setElements,
newElement,
elementId
};
return(
<ElementContext.Provider value={value}>
{children}
</ElementContext.Provider>
)
};
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((elements, elementId) => <Todobox key={elementId} />)}
</div>
</div>
)
}
Todobox.jsx:
import React from 'react';
import Item from './Item';
import { useContext } from 'react';
import '../App.css';
import { ElementContext } from '../ElementContext';
export default function Todobox(){
const { elements, setElements, newElement, elementId } = useContext(ElementContext);
return(
<div className='element-box'>
<a className='element-title'>PlaceHolder</a>
<Item />
<textarea
className='element-input'
type='text'
placeholder={elements.boxid}
/>
</div>
)
}
I am pretty new to react and such so any help is appreciated!
CodePudding user response:
The elements
array in state (and context) is an array of objects, and those objects have a boxid
property. To use it, you need to reference or pass down that property when iterating over the elements. So your starting point would be to change this line:
elements.map((elements, elementId) => <Todobox key={elementId} />)
I'd change Todobox
so that it doesn't use context at all, and is instead passed down all values it needs to render from the parent, including the boxid
.
Other issues:
- The
.map
callback parameter is not an array - it's a single object, so it should probably be calledelement
, notelements
, to avoid confusion - Keys should usually not be the index of the element in the array. Use a more unique identifier, such as the
boxid
, which will never change for a particular object. (In your current implementation, theelementId
in the.map
callback may not reflect the actualboxid
of the object being iterated over, if you ever remove an item from the middle of the state array.)
elements.map((element) => <Todobox key={element.boxid} boxid={element.boxid} />)
export default function Todobox({ boxid }){
return(
<div className='element-box'>
<a className='element-title'>PlaceHolder</a>
<Item />
<textarea
className='element-input'
type='text'
placeholder={boxid}
/>
</div>
)
}