#reactjs #react-hooks
#reactjs #react-перехваты
Вопрос:
На самом деле у меня есть список элементов, которые должны храниться в массиве как состояние реакции.
const [data, setData] = useState([{"name": "joy", "age": 25}, {"name": "tom", "age": 41}]);
Каким-то образом мне нужно обновить только определенный объект, может быть имя или возраст.
Я делаю таким образом. Но это кажется не очень хорошим.
setData(prevState => {
let obj = prevState.find(o => anycondition);
if(obj !== undefined) {
obj.name = "Demo";
}
return [...prevState];
})
есть ли какой-либо другой способ обновить только объект из массива состояний с помощью реактивных перехватов?
Ответ №1:
Это изменение состояния!!
setData(prevState => {
let obj = prevState.find(o => anycondition);
if(obj !== undefined) {
obj.name = "Demo"; // <-- state mutation
}
return [...prevState];
})
Всегда следует неглубоко копировать текущее состояние, которое обновляется
setData(prevState => {
return prevState.map(el => <condition> ? { // <-- map state to new array
...el, // <-- copy element
name: "Demo", // <-- write new property
} : el);
})
Если вам нужно выполнить какие-либо вычисления в рамках обратного вызова map, предоставьте обратному вызову обычное тело функции и добавьте любую необходимую логику.
setData(prevState => {
return prevState.map(el => { // <-- map state to new array
// any mapping logic
...
if (<condition>) {
// any other logic
...
return {
...el, // <-- copy element
name: "Demo", // <-- write new property
}
} else {
return el;
}
});
})
Комментарии:
1. Как выполнить какие-либо вычисления при отображении prevState?
2. @user10328862 Любое вычисление может быть выполнено в обратном вызове map. Что вы пытаетесь вычислить?
3. Можете ли вы упростить свой код ответа, добавив условие if else?
4. @user10328862 Ты имеешь в виду сравнение с троичным использованием?
5. @user10328862 обновил ответ с возможным примером использования if-else.
Ответ №2:
Может быть, вы хотите что-то вроде этого?
здесь вы будете выполнять цикл только один раз и обновлять данные, которые вы хотите
changeHandler = event => {
const [name, value] = event.target.name
setData(prevState => prevState.map(item => {
if (anycondition) {
return {
...item,
[name]: value
}
}
return item
}))
}
Если вы также хотите получить некоторый идентификатор из входных данных, вы можете передать его с наборами данных, как здесь data-id={1}
А затем получить его из события, подобного этому, const id = e.target.dataset.id;
в changeHandler
функции
<input
type="text"
name="name"
data-id={1}
value={this.state.data.name.fname}
onChange={this.changeHandler}
/>
Ответ №3:
Чтобы справиться с этим с большим контролем, вы можете добавить идентификатор prop к каждому объекту.
Если вы хотите изменить конкретный объект, просто сделайте:
const [data, setData] = useState([
{
id: 1,
name: "joy",
age: 25
},
{
id: 2,
name: "tom",
age: 41
}
]);
const updateItem = (id, attributes) => {
const index = data.findIndex(item => item.id === id);
if (index === -1)
return;
setData(
[
...data.slice(0, index),
Object.assign({}, data[index], attributes),
...data.slice(index 1)
]
);
}
// You can update the second item as follows
updateItem(2, { age: 50 })
Комментарии:
1. Кроме того, вы можете продолжить без идентификатора, но вам придется искать элемент с вашим собственным условием.
2. Хотя этот код все еще выполняет поиск по условию (соответствует
id
), и выполняет еще несколько проходов по данным, чем это действительно необходимо. 1 проход для поиска индекса, 2 прохода для копирования до индекса и среза затем распространения в новый массив, 2 прохода для копирования после индекса и среза затем распространения в новый массив.3. @VictorMolina Вы путаете this.state с useState и, вероятно, лучше использовать Array.prototype.map для обновления элемента массива
Ответ №4:
попробуйте этот способ 😉
function mergeState(state, payload) {
return { ...state, ...payload }
}
const [state, dispatch] = useReducer(mergeState, {
name: '',
age: 0,
data: [{"name": "joy", "age": 25}, {"name": "tom", "age": 41}],
})
// get the data
const data = state.data.map(item => {
if(obj !== undefined){
obj.name = "Demo";
}
return item
})
// update
dispatch({data})