Reputation: 1667
I'm working on a basic react project, where I have react state with object and array, what I'm trying to get done here is I want to push the object to the images
array, and I want to render that in component, so far I googled things I found few methods to get it done array.concat
and array.push
, I tried both methods it's updating the state but it's not affecting on the component
here below is the code I had tried
const [proClrData, setProClrData] = useState([
{ color: "black", price: "", qty: "", images: [] },
{ color: "white", price: "", qty: "", images: [] },
{ color: "red", price: "", qty: "", images: [] }
]);
const addImages = (key) => {
var obj = { src: "", imgdata: "" };
proClrData[key].images = proClrData[key].images.concat(obj);
console.log(proClrData);
};
below is component code
{proClrData.length >= 1 &&
proClrData?.map((clr, key) => {
return (
<div key={key}>
<p className="pt-3 ">{clr.color}</p>
<div className="form-group">
<input
label="Price"
name="price"
value={clr?.price}
type="number"
fullWidth
required
/>
</div>
<div className="form-group pt-3">
<input
label="Quantity"
name="qty"
value={clr?.qty}
type="number"
fullWidth
required
/>
</div>
<div className="text-end pt-3">
<button
variant="contained"
color="primary"
onClick={() => addImages(key)}
>
Add Images
</button>
</div>
{clr?.images?.map((img, imgkey) => {
return (
<div className="form-group pt-3" key={imgkey}>
<input
label="Image"
name="images"
value=""
accept="image/*"
type="file"
fullWidth
required
/>
</div>
);
})}
</div>
);
})}
here is codeSandbox of working code.
Upvotes: 1
Views: 64
Reputation: 202608
You are mutating your state object and then not updating state at all.
const addImages = (key) => {
var obj = { src: "", imgdata: "" };
proClrData[key].images = proClrData[key].images.concat(obj); // mutation!!
console.log(proClrData);
};
Enqueue a state update with the new image data you want in state. Use a functional state update to update from the previous state. Shallow copy the proClrData
array, and for the matching element, also shallow copy it so it is a new object reference, and then also shallow copy the nested images
array and append the new object.
const [proClrData, setProClrData] = useState([
{ color: "black", price: "", qty: "", images: [] },
{ color: "white", price: "", qty: "", images: [] },
{ color: "red", price: "", qty: "", images: [] }
]);
const addImages = (key) => {
const obj = { src: "", imgdata: "" };
setProClrData(data => data.map((el, i) => i === key ? {
...el,
images: [...el.images, obj],
} : el));
};
Since React state updates are asynchronously processed, you will want to move the console log into an useEffect
hook to log the state after it updates and is available on the next render.
useEffect(() => {
console.log(proClrData);
}, [proClrData]);
Upvotes: 1
Reputation: 18083
you must call setProClrData
function to update the state.
Remember that you must not mutate the state, instead you must provide a new reference (a new array in your case) and call the updater function, otherwise React will not be aware that is should re-render the component.
const [proClrData, setProClrData] = useState([
{ color: "black", price: "", qty: "", images: [] },
{ color: "white", price: "", qty: "", images: [] },
{ color: "red", price: "", qty: "", images: [] }
]);
const addImages = (key) => {
const img = { src: "", imgdata: "" };
const newProClrData = proClrData.map((obj, index) => {
return index !== key ? data : { ...obj, images: [...data.images, img] };
});
setProClrData(newProClrData);
};
Upvotes: 1
Reputation: 192
You update the state directly
Use the function for this:
setProClrData(prev => prev.push() // or concat)
Upvotes: 0
Reputation: 524
You should modify proClrData accordingly and be using setProClrData in order to trigger a re-render.
Check the documentation: https://reactjs.org/docs/hooks-state.html
Upvotes: 0