Related
I have retrieved data stored using useState in an array of object, the data was then outputted into form fields. And now I want to be able to update the fields (state) as I type.
I have seen examples on people updating the state for property in array, but never for state in an array of object, so I don't know how to do it. I've got the index of the object passed to the callback function but I didn't know how to update the state using it.
// sample data structure
const data = [
{
id: 1,
name: 'john',
gender: 'm'
}
{
id: 2,
name: 'mary',
gender: 'f'
}
]
const [data, setData] = useState([]);
const updateFieldChanged = index => e => {
console.log('index: ' + index);
console.log('property name: '+ e.target.name);
setData() // ??
}
return (
<React.Fragment>
{data.map((data, index) => {
<li key={data.name}>
<input type="text" name="name" value={data.name} onChange={updateFieldChanged(index)} />
</li>
})}
</React.Fragment>
)
Here is how you do it:
// sample data structure
/* const data = [
{
id: 1,
name: 'john',
gender: 'm'
}
{
id: 2,
name: 'mary',
gender: 'f'
}
] */ // make sure to set the default value in the useState call (I already fixed it)
const [data, setData] = useState([
{
id: 1,
name: 'john',
gender: 'm'
}
{
id: 2,
name: 'mary',
gender: 'f'
}
]);
const updateFieldChanged = index => e => {
console.log('index: ' + index);
console.log('property name: '+ e.target.name);
let newArr = [...data]; // copying the old datas array
// a deep copy is not needed as we are overriding the whole object below, and not setting a property of it. this does not mutate the state.
newArr[index] = e.target.value; // replace e.target.value with whatever you want to change it to
setData(newArr);
}
return (
<React.Fragment>
{data.map((datum, index) => {
<li key={datum.name}>
<input type="text" name="name" value={datum.name} onChange={updateFieldChanged(index)} />
</li>
})}
</React.Fragment>
)
The accepted answer leads the developer into significant risk that they will mutate the source sequence, as witnessed in comments:
let newArr = [...data];
// oops! newArr[index] is in both newArr and data
// this might cause nasty bugs in React.
newArr[index][propertyName] = e.target.value;
This will mean that, in some cases, React does not pick up and render the changes.
The idiomatic way of doing this is by mapping your old array into a new one, swapping what you want to change for an updated item along the way.
setData(
data.map(item =>
item.id === index
? {...item, someProp : "changed", someOtherProp: 42}
: item
))
setDatas(datas=>({
...datas,
[index]: e.target.value
}))
with index being the target position and e.target.value the new value
You don't even need to be using the index ( except for the key if you want ) nor copying the old datas array,and can even do it inline or just pass data as an argument if you prefer updateFieldChanged to not be inline. It's done very quickly that way :
const initial_data = [
{
id: 1,
name: "john",
gender: "m",
},
{
id: 2,
name: "mary",
gender: "f",
},
];
const [datas, setDatas] = useState(initial_data);
return (
<div>
{datas.map((data, index) => (
<li key={index}>
<input
type="text"
value={data.name}
onChange={(e) => {
data.name = e.target.value;
setDatas([...datas]);
}}
/>
</li>
))}
</div>
);
};
This is what I do:
const [datas, setDatas] = useState([
{
id: 1,
name: "john",
gender: "m",
},
{
id: 2,
name: "mary",
gender: "f",
},
]);
const updateFieldChanged = (name, index) => (event) => {
let newArr = datas.map((item, i) => {
if (index == i) {
return { ...item, [name]: event.target.value };
} else {
return item;
}
});
setDatas(newArr);
};
return (
<React.Fragment>
{datas.map((data, index) => {
<li key={data.name}>
<input
type="text"
name="name"
value={data.name}
onChange={updateFieldChanged("name", index)}
/>
</li>;
<li key={data.gender}>
<input
type="text"
name="gender"
value={data.gender}
onChange={updateFieldChanged("gender", index)}
/>
</li>;
})}
</React.Fragment>
);
Spread the array before that. As you cannot update the hook directly without using the method returned by useState
const newState = [...originalState]
newState[index] = newValue
setOriginalState(newState)
This will modify the value of the state and update the useState hook if its an array of string.
const updateFieldChanged = index => e => {
name=e.target.name //key
let newArr = [...data]; // copying the old datas array
newArr[index][name] = e.target.value; //key and value
setData(newArr);
}
return (
<React.Fragment>
{data.map((datum, index) => {
<li key={datum.name}>
<input type="text" name="name" value={datum.name} onChange={updateFieldChanged(index)} />
</li>
})}
</React.Fragment>
)
const [datas, setDatas] = useState([ { id: 1, name: 'john', gender: 'm' } { id: 2, name: 'mary', gender: 'f' } ]);
const updateFieldChanged = (index, e) => { const updateData = { ...data[index], name: e.target.name }
setData([...data.slice(0, index), updateData, ...data.slice(index + 1)]) }
I am late to reply but I had also same problem, so I got solution through this query. Have a look on it if it can help you.The example that I did is that I have a state , named OrderList, and so a setter for it is SetOrderList. To update a specific record in a list, am using SetOrderList and passing it a map function with that list of which I need to change, so I will compare Index or Id of my list, where it will match, I will change that specific record.
const Action = (Id, Status) => { //`enter code here`Call this function onChange or onClick event
setorderList([...orderList.map((order) =>
order.id === Id ? { ...order, status: Status } : order
),
]);
}
complete example for update value based on index and generate input based on for loop....
import React, { useState,useEffect } from "react";
export default function App() {
const [datas, setDatas] =useState([])
useEffect(() => {
console.log("datas");
console.log(datas);
}, [datas]);
const onchangeInput = (val, index) =>{
setDatas(datas=>({
...datas,
[index]: val.target.value
}))
console.log(datas);
}
return (
<>
{
(() => {
const inputs = [];
for (let i = 0; i < 20; i++){
console.log(i);
inputs.push(<input key={i} onChange={(val)=>{onchangeInput(val,i)}} />);
}
return inputs;
})()
}
</>
);
}
const MyCount = () =>{
const myData = [
{
id: 1,
name: 'john',
gender: 'm'
},
{
id: 2,
name: 'mary',
gender: 'f'
}
]
const [count, setCount] = useState(0);
const [datas, setDatas] = useState(myData);
const clkBtn = () =>{
setCount((c) => c + 1);
}
return(
<div>
<button onClick={clkBtn}>+ {count}</button>
{datas.map((data, index) => (
<li key={index}>
<input
type="text"
value={data.name}
onChange={(e) => {
data.name = e.target.value;
setDatas([...datas]);
}}
/>
</li>
))}
</div>
)
}
Base on #Steffan, thus use as your way:
const [arr,arrSet] = useState(array_value);
...
let newArr = [...arr];
arr.map((data,index) => {
newArr[index].somename= new_value;
});
arrSet(newArr);
Use useEffect to check new arr value.
A little late to the party, but it is an option to spread the contents of the array in a new object, then replacing the desired object in the selected index and finally producing an array from that result, it is a short answer, probably not the best for large arrays.
// data = [{name: 'tom', age: 15, etc...}, {name: 'jerry', age: 10, etc...}]
// index = 1
setData(Object.values({...data, [index]: {...data[index], name: 'the mouse' }}))
// data = [{name: 'tom', age: 15, etc...}, {name: 'the mouse', age: 10, etc...}]
I am trying to test my understanding of React but hit a mental block. Would it be possible to create a unique key / id within my <FormInput> component rather than creating the unique ID inside the <MainUI> component once the newly created item is passed up into <MainUI>? I find that weird and definitely feel like there is a way better method of doing this.
const MainUI = props => {
const receiveNewItem = enteredNewItem => {
const newItem = {
...enteredNewItem,
id: Math.random().toString()
}
props.addNewItem(newItem)
}
console.log(props.data)
return(
<div>
<FormInput receiveNewItem={receiveNewItem}/>
{/* <MaxAmount data={props.data} /> */}
<DisplayItems data={props.data} key={props.data.id} />
</div>
)
}
export default MainUI;
import { useState } from 'react'
import Card from './Card'
const FormInput = props => {
const [userInput, setUserInput] = useState({
name: '',
amount: '',
date: ''
})
const nameInputHandler = e => {
setUserInput( prevObj => {
return {...prevObj, name: e.target.value}
})
}
const amountInputHandler = e => {
setUserInput( prevObj => {
return {...prevObj, amount: e.target.value}
})
}
const dateInputHandler = e => {
setUserInput( prevObj => {
return {...prevObj, date: e.target.value}
})
}
const submitHandler = e => {
e.preventDefault()
props.receiveNewItem(userInput)
setUserInput( prevObj => { return {...prevObj, name: ''}})
}
return (
<Card>
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Name Input"
value={userInput.name}
onChange={nameInputHandler} />
<input
type="number"
placeholder="Amount Input"
value={userInput.amount}
onChange={amountInputHandler} />
<input
type="date"
placeholder="Date Input"
value={userInput.date}
onChange={dateInputHandler} />
<button>Add Item</button>
</form>
</Card>
)
}
export default FormInput;
const { useReducer } = React
const InputWithLabelAbove = ({
labelText,
id,
onChange,
pattern,
value,
}) => {
return (
<label htmlFor={id}>
{labelText}
<div>
<input
type="text"
id={id}
pattern={pattern}
value={value}
onChange={onChange}
/>
</div>
</label>
)
}
const MemoInputWithLabelAbove = React.memo(InputWithLabelAbove)
const Component = () => {
// calc object
const calculatorObj = {
tax: '',
water: '',
energy: '',
internet: '',
transport: '',
food: '',
education: '',
childcare: '',
otherInsurance: '',
otherCosts: ''
}
// state
const inputValues = {
total: '',
showCalculator: false,
calculatedTotal: 0,
calc: {
...calculatorObj
}
}
// reducer for form states
const [values, setValues] = useReducer(
(state, newState) => ({...state, ...newState}),
inputValues
)
// on change function to handle field states.
const handleChange = React.useCallback((e, type) => {
const { value, id } = e.target
console.log('onchange')
const re = /^[0-9\b]+$/
const converted = !re.test(value) || value.length === 0 ? '' : parseInt(value, 10)
if (type === 'calculator') {
const obj = {
...values.calc,
[id]: converted
}
setValues({ calc: { ...obj }})
}
}, [values.calc])
const calcLabelArr = ['Council tax', 'Water', 'Energy (gas and/or electricity)', 'Internet', 'Transport', 'Food', 'Children\'s education', 'Childcare', 'Other insurance', 'Other essential costs']
return (
<div
style={{ width: '60%', marginBottom: '20px', position: 'relative' }}
>
{ Object.entries(values.calc).map((i, index) => {
return <div key={calcLabelArr[index]}>
<MemoInputWithLabelAbove
id={i[0]}
type="text"
labelText={calcLabelArr[index]}
onChange={(e) => handleChange(e, 'calculator')}
value={i[1]}
/>
</div>
}
)}
</div>
)
}
ReactDOM.render(
<Component />,
document.getElementById('reactBind')
)
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="reactBind"></div>
Below is the rendering of the inputs using an array (with 10 elements) so 10 input elements are rendered.
// calculator object typically populated but for this example its empty for ease.
const calcLabelArr = []
// function to return calculator fields
const buildView = () => {
return (
<Col
xs="12"
md={{ span: 6, offset: 3 }}
style={{ marginBottom: '20px', position: 'relative' }}
>
{ Object.entries(values.calc).map((i, index) => {
return <div key={calcLabelArr[index]}>
<InputWithLabelAbove
id={i[0]}
type="text"
labelPosition="top"
labelText={calcLabelArr[index]}
onChange={(e) => handleChange(e, 'calculator')}
value={i[1]}
/>
</div>
}
)}
</Col>
)
}
Below is the onChange function used to set that state of each input.
const handleChange = React.useCallback((e, type) => {
const { value, id } = e.target
const re = /^[0-9\b]+$/
const converted = !re.test(value) || isEmpty(value) ? '' : parseInt(value, 10)
if (type === 'calculator') {
const obj = {
...values.calc,
[id]: converted
}
setValues({ calc: { ...obj }})
} else {
setValues({
total: converted,
})
}
}, [values.calc])
Below is the component that is memoized.
import React from 'react'
import { join } from 'lodash'
import { Label, StyledInput, Red } from './style'
export type IProps = {
labelPosition: string,
labelText: string,
id: string,
hasErrored?: boolean,
onChange: () => void,
dataUxId?: string,
pattern?: string,
sessioncamHide?: boolean,
sessioncamClassList?: string | string[],
value?: string,
validation?: boolean,
}
const InputWithLabelAbove: React.FC<IProps> = ({
labelPosition,
labelText,
id,
hasErrored,
onChange,
dataUxId,
pattern,
sessioncamHide,
sessioncamClassList,
value,
validation,
}) =>
(
<Label hasErrored={hasErrored} labelPosition={labelPosition} htmlFor={id}>
{labelText && (<span>{labelText}{validation && (<Red>*</Red>)}</span>)}
<div>
<StyledInput
type="text"
id={id}
hasErrored={hasErrored}
dataUxId={`InputText_${dataUxId}`}
pattern={pattern}
labelPosition={labelPosition}
value={value}
onInput={onChange}
onChange={onChange}
/>
</div>
</Label>
)
export const MemoInputWithLabelAbove = React.memo(InputWithLabelAbove)
As you can see, it isn't the key I don't think that is causing the re-render, my input component is memoized and the onChange is using a callback, however on using the react profiler, every onChange re-renders all my input components. Could someone elaborate to why this is?
One thing that jumps out is this property on the input component:
onChange={(e) => handleChange(e, 'calculator')}
Even though handleChange is memoized, you're creating a new arrow function every time to call the memoized function. So even if the input is memoized, it's seeing a new onChange every time.
You'd need to pass a stable function to avoid re-rendering, for instance:
const onChange = React.useCallback(
e => handleChange(e, "calculator"),
[handleChange]
);
and then
onChange={onChange}
(It wasn't clear to me where you're defining handleChange; if it's within the component that's rendering these inputs, you can probably combine that definition with the above in a single useCallback or possible useMemo if it's multiple callbacks. Although small pieces are good too.)
My react application take data from user and should output them when user click on SUBMIT button.
Now user open the application appears a number input. There he can set a number, for example 2. After that appears 2 boxes, where user can add fields cliking on the button +. In each field user have to add his name and last name. Now the application works, but no in the right way.
Now, if user add his user name and last name in first box and click on SUBMIT, everithing appears in:
const onFinish = values => {
const res = {
data: [dataAll]
};
console.log("Received values of form:", res);
};
But if user add one another inputs clicking on add fields button, the first data dissapears. The same issue is when user add data in 2 boxes, the data is saved just from the last box.
function handleInputChange(value) {
const newArray = Array.from({ length: value }, (_, index) => index + 1);
setNr(newArray);
}
const onFinish = values => {
const res = {
data: [dataAll]
};
console.log("Received values of form:", res);
};
return (
<div>
<Form name="outter" onFinish={onFinish}>
{nr.map(i => (
<div>
<p key={i}>{i}</p>
<Child setDataAll={setDataAll} nr={i} />
</div>
))}
<Form.Item
name={["user", "nr"]}
label="Nr"
rules={[{ type: "number", min: 0, max: 7 }]}
>
<InputNumber onChange={handleInputChange} />
</Form.Item>
<Form.Item>
<Button htmlType="submit" type="primary">
Submit
</Button>
</Form.Item>
</Form>
</div>
);
};
Mu expected result after clicking on submit is:
data:[
{
nr:1,
user: [
{
firstName:'John',
lastName: 'Doe'
},
{
firstName:'Bill',
lastName: 'White'
}
]
},
{
nr:2,
user: [
{
firstName:'Carl',
lastName: 'Doe'
},
{
firstName:'Mike',
lastName: 'Green'
},
{
firstName:'Sarah',
lastName: 'Doe'
}
]
},
]
....
// object depend by how many fields user added in each nr
Question: How to achieve the above result?
demo: https://codesandbox.io/s/wandering-wind-3xgm7?file=/src/Main.js:288-1158
Here's an example how you could do it.
As you can see Child became Presentational Component and only shows data.
Rest of logic went to the Parent component.
const { useState, useEffect, Fragment } = React;
const Child = ({nr, user, onAddField, onChange}) => {
return <div>
<div>{nr}</div>
{user.map(({firstName, lastName}, index) => <div key={index}>
<input onChange={({target: {name, value}}) => onChange(nr, index, name, value)} value={firstName} name="firstName" type="text"/>
<input onChange={({target: {name, value}}) => onChange(nr, index, name, value)} value={lastName} name="lastName" type="text"/>
</div>)}
<button onClick={() => onAddField(nr)}>Add Field</button>
</div>
}
const App = () => {
const [items, setItems] = useState([
{
nr: 1,
user: []
},
{
nr: 2,
user: [
{firstName: 'test1', lastName: 'test1'},
{firstName: 'test2', lastName: 'test2'}
]
}
]);
const onCountChange = ({target: {value}}) => {
setItems(items => {
const computedList = Array(Number(value)).fill(0).map((pr, index) => ({
nr: index + 1,
user: []
}))
const merged = computedList.reduce((acc, value) => {
const item = items.find(pr => pr.nr === value.nr) || value;
acc = [...acc, item];
return acc;
}, [])
return merged;
})
}
const onChildChange = (nr, index, name, value) => {
setItems(items => {
const newItems = [...items];
const item = newItems.find(pr => pr.nr === nr);
const field = item.user.find((pr, ind) => index === ind)
field[name] = value;
return newItems;
});
}
const onAddField = (nr) => {
setItems(items => {
const newItems = [...items];
const item = newItems.find(pr => pr.nr === nr);
item.user = [...item.user, {
firstName: '',
lastName: ''
}];
return newItems;
})
}
const onClick = () => {
console.log({data: items});
}
return <div>
{items.map((pr, index) => <Child {...pr} onAddField={onAddField} onChange={onChildChange} key={index} />)}
<input onChange={onCountChange} value={items.length} type="number"/>
<button onClick={onClick}>Submit</button>
</div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>
I have retrieved data stored using useState in an array of object, the data was then outputted into form fields. And now I want to be able to update the fields (state) as I type.
I have seen examples on people updating the state for property in array, but never for state in an array of object, so I don't know how to do it. I've got the index of the object passed to the callback function but I didn't know how to update the state using it.
// sample data structure
const data = [
{
id: 1,
name: 'john',
gender: 'm'
}
{
id: 2,
name: 'mary',
gender: 'f'
}
]
const [data, setData] = useState([]);
const updateFieldChanged = index => e => {
console.log('index: ' + index);
console.log('property name: '+ e.target.name);
setData() // ??
}
return (
<React.Fragment>
{data.map((data, index) => {
<li key={data.name}>
<input type="text" name="name" value={data.name} onChange={updateFieldChanged(index)} />
</li>
})}
</React.Fragment>
)
Here is how you do it:
// sample data structure
/* const data = [
{
id: 1,
name: 'john',
gender: 'm'
}
{
id: 2,
name: 'mary',
gender: 'f'
}
] */ // make sure to set the default value in the useState call (I already fixed it)
const [data, setData] = useState([
{
id: 1,
name: 'john',
gender: 'm'
}
{
id: 2,
name: 'mary',
gender: 'f'
}
]);
const updateFieldChanged = index => e => {
console.log('index: ' + index);
console.log('property name: '+ e.target.name);
let newArr = [...data]; // copying the old datas array
// a deep copy is not needed as we are overriding the whole object below, and not setting a property of it. this does not mutate the state.
newArr[index] = e.target.value; // replace e.target.value with whatever you want to change it to
setData(newArr);
}
return (
<React.Fragment>
{data.map((datum, index) => {
<li key={datum.name}>
<input type="text" name="name" value={datum.name} onChange={updateFieldChanged(index)} />
</li>
})}
</React.Fragment>
)
The accepted answer leads the developer into significant risk that they will mutate the source sequence, as witnessed in comments:
let newArr = [...data];
// oops! newArr[index] is in both newArr and data
// this might cause nasty bugs in React.
newArr[index][propertyName] = e.target.value;
This will mean that, in some cases, React does not pick up and render the changes.
The idiomatic way of doing this is by mapping your old array into a new one, swapping what you want to change for an updated item along the way.
setData(
data.map(item =>
item.id === index
? {...item, someProp : "changed", someOtherProp: 42}
: item
))
setDatas(datas=>({
...datas,
[index]: e.target.value
}))
with index being the target position and e.target.value the new value
You don't even need to be using the index ( except for the key if you want ) nor copying the old datas array,and can even do it inline or just pass data as an argument if you prefer updateFieldChanged to not be inline. It's done very quickly that way :
const initial_data = [
{
id: 1,
name: "john",
gender: "m",
},
{
id: 2,
name: "mary",
gender: "f",
},
];
const [datas, setDatas] = useState(initial_data);
return (
<div>
{datas.map((data, index) => (
<li key={index}>
<input
type="text"
value={data.name}
onChange={(e) => {
data.name = e.target.value;
setDatas([...datas]);
}}
/>
</li>
))}
</div>
);
};
This is what I do:
const [datas, setDatas] = useState([
{
id: 1,
name: "john",
gender: "m",
},
{
id: 2,
name: "mary",
gender: "f",
},
]);
const updateFieldChanged = (name, index) => (event) => {
let newArr = datas.map((item, i) => {
if (index == i) {
return { ...item, [name]: event.target.value };
} else {
return item;
}
});
setDatas(newArr);
};
return (
<React.Fragment>
{datas.map((data, index) => {
<li key={data.name}>
<input
type="text"
name="name"
value={data.name}
onChange={updateFieldChanged("name", index)}
/>
</li>;
<li key={data.gender}>
<input
type="text"
name="gender"
value={data.gender}
onChange={updateFieldChanged("gender", index)}
/>
</li>;
})}
</React.Fragment>
);
Spread the array before that. As you cannot update the hook directly without using the method returned by useState
const newState = [...originalState]
newState[index] = newValue
setOriginalState(newState)
This will modify the value of the state and update the useState hook if its an array of string.
const updateFieldChanged = index => e => {
name=e.target.name //key
let newArr = [...data]; // copying the old datas array
newArr[index][name] = e.target.value; //key and value
setData(newArr);
}
return (
<React.Fragment>
{data.map((datum, index) => {
<li key={datum.name}>
<input type="text" name="name" value={datum.name} onChange={updateFieldChanged(index)} />
</li>
})}
</React.Fragment>
)
const [datas, setDatas] = useState([ { id: 1, name: 'john', gender: 'm' } { id: 2, name: 'mary', gender: 'f' } ]);
const updateFieldChanged = (index, e) => { const updateData = { ...data[index], name: e.target.name }
setData([...data.slice(0, index), updateData, ...data.slice(index + 1)]) }
I am late to reply but I had also same problem, so I got solution through this query. Have a look on it if it can help you.The example that I did is that I have a state , named OrderList, and so a setter for it is SetOrderList. To update a specific record in a list, am using SetOrderList and passing it a map function with that list of which I need to change, so I will compare Index or Id of my list, where it will match, I will change that specific record.
const Action = (Id, Status) => { //`enter code here`Call this function onChange or onClick event
setorderList([...orderList.map((order) =>
order.id === Id ? { ...order, status: Status } : order
),
]);
}
complete example for update value based on index and generate input based on for loop....
import React, { useState,useEffect } from "react";
export default function App() {
const [datas, setDatas] =useState([])
useEffect(() => {
console.log("datas");
console.log(datas);
}, [datas]);
const onchangeInput = (val, index) =>{
setDatas(datas=>({
...datas,
[index]: val.target.value
}))
console.log(datas);
}
return (
<>
{
(() => {
const inputs = [];
for (let i = 0; i < 20; i++){
console.log(i);
inputs.push(<input key={i} onChange={(val)=>{onchangeInput(val,i)}} />);
}
return inputs;
})()
}
</>
);
}
const MyCount = () =>{
const myData = [
{
id: 1,
name: 'john',
gender: 'm'
},
{
id: 2,
name: 'mary',
gender: 'f'
}
]
const [count, setCount] = useState(0);
const [datas, setDatas] = useState(myData);
const clkBtn = () =>{
setCount((c) => c + 1);
}
return(
<div>
<button onClick={clkBtn}>+ {count}</button>
{datas.map((data, index) => (
<li key={index}>
<input
type="text"
value={data.name}
onChange={(e) => {
data.name = e.target.value;
setDatas([...datas]);
}}
/>
</li>
))}
</div>
)
}
Base on #Steffan, thus use as your way:
const [arr,arrSet] = useState(array_value);
...
let newArr = [...arr];
arr.map((data,index) => {
newArr[index].somename= new_value;
});
arrSet(newArr);
Use useEffect to check new arr value.
A little late to the party, but it is an option to spread the contents of the array in a new object, then replacing the desired object in the selected index and finally producing an array from that result, it is a short answer, probably not the best for large arrays.
// data = [{name: 'tom', age: 15, etc...}, {name: 'jerry', age: 10, etc...}]
// index = 1
setData(Object.values({...data, [index]: {...data[index], name: 'the mouse' }}))
// data = [{name: 'tom', age: 15, etc...}, {name: 'the mouse', age: 10, etc...}]