#reactjs #react-hooks
#reactjs #реагирующие хуки
Вопрос:
Заранее приношу извинения, если на эти вопросы уже были даны ответы ранее (а также за длинный пост, но я старался быть максимально конкретным). Но ответы, которые я нашел, меня не полностью удовлетворяют.
Я хочу использовать новые удивительные хуки React для своего проекта. И то, что я делал до сих пор, было прямым.
Теперь я столкнулся с более сложным примером, и я не уверен, как мне лучше всего справиться с этим.
Допустим, у меня более сложный объект (по крайней мере, он не плоский) в моем состоянии.
{
persons: [
{
id: 1,
name: 'Joe Doe',
age: 35,
country: 'Spain',
interests: [
{ id: 1, en: 'Football', es: 'Fútbol' },
{ id: 2, en: 'Travelling', es: 'Viajar' }
]
},
{
id: 2,
name: 'Foo Bar',
age: 28,
country: 'Spain',
interests: [
{ id: 3, en: 'Computers', es: 'Computadoras' },
{ id: 4, en: 'Cooking', es: 'Cocinar' }
]
}
],
amount: 2,
foo: 'bar'
}
Каков наилучший способ:
- Добавьте элемент (объект) в массив моих коллег
- Добавить элемент в определенный массив «интересов»?
- Манипулировать значением свойства внутри объекта в массиве?
- Изменить значение вне массива persons, например
foo
?
используя перехват useState?
Следующие примеры кода попытаются проиллюстрировать каждый вопрос. Они не тестировались…
Давайте рассмотрим, что у меня есть контейнер, который начинается с этого. Он также включает в себя функции, которые разделены в остальной части поста.
const [colleagues, setColleagues] = useState({});
// using the useEffect as "componentDidMount
useEffect(() => {
// receiving data from ajax request
// and set the state as the example object provided earlier
setColleagues(response.data);
}, []);
1) Итак, что касается первого вопроса. Это допустимо?
Или мне нужно убедиться, что каждый объект в моем persons array
разрушен?
const onAddNewColleague = () => {
// new colleague, this data would be dynamic
// but for the sake of this example I'll just hard code it
const newColleague = {
name: 'Foo Baz Bar',
age: 30,
country: 'Spain',
interests: [
{ en: 'Cats', es: 'Gatos' }
]
};
// creates a copy of the state
// targets the "persons" prop and adds a new array
// where the new colleague is appended
const newState = {
...colleagues,
persons: colleagues.concat(newColleague)
};
// updates the state
setColleagues(newState);
};
2) This feels wrong as I end up updating the entire persons array
instead of just the interest array
for a specific person.
const onAddNewInterest = (personId) => {
// a new interest
const newInterest = {
en: 'Languages', es: 'Idiomas'
};
// find the person according to personId
// and update the interests
const updatedPersons = colleagues.persons.map(person => {
if(person.id === personId) {
return {
...person,
interests: person.interests.concat(newInterest);
};
}
return person;
});
// create a copy of the state
const newState = {
...colleagues,
persons: [...updatedPersons]
};
setColleagues(newState);
};
3) В качестве второго примера этот тоже кажется неправильным, поскольку я обновляюсь полностью, persons array
когда на самом деле я мог бы просто захотеть изменить age
одного конкретного человека
const onChangeValue = (personId, key, value) => {
// find the person
const updatedPersons = colleagues.persons.map(person => {
if(person.id === personId) {
// key, could be age?
return {
...person,
[key]: value
};
}
return person;
});
// create a copy of the state
const newState = {
...colleagues,
persons: [...updatedPersons]
};
setColleagues(newState);
};
4) Это допустимо, или мне нужно уничтожить каждую часть моего colleagues object
по отдельности?
const onChangeOtherValue = (key, value) => {
// for example changing the value foo
const newState = {
...colleagues,
[key]: value
};
setColleagues(newState);
};
У меня действительно есть ощущение, что только концепция первой функции допустима, в то время как остальные из них — нет.
Можно ли это сделать легко, или я должен просто использовать неизменяемый помощник?
Заранее спасибо!
Обновлены примеры, чтобы получить синтаксис, верно. Спасибо, Валерий.
Чтобы прояснить, что мне действительно нужно, вот лучшая практика для обработки вариантов использования, подобных этому. Я хочу убедиться, что мое состояние обновляется наиболее правильным и эффективным способом. Так что не стесняйтесь разбирать мои примеры на части или писать новые — я весь внимание. Нет необходимости просто модифицировать мой, чтобы он соответствовал этому сообщению (если только они на самом деле не окажутся хорошими).
Комментарии:
1. Вы рассматривали возможность использования
useReducer
хука? Это упростит более сложный переход состояния, поскольку вы можете предоставить более полный набор переходов и переместить логику за пределы компонента2. Привет! Я заглянул в useReducer, и это тоже классный хук! Но мне все еще нужно убедиться, что мое состояние обновляется неизменяемым образом, верно? Именно в этом вложенном состоянии я чувствую неуверенность.. Не стесняйтесь добавлять пример 🙂
3. То, что вы хотите, вероятно, называется «структурное совместное использование» — используйте как можно больше и копируйте только то, что необходимо.
Ответ №1:
1) ОК
2)
const updatedPersons = colleagues.persons.map(person => {
if(person.id === personId) {
return {
...person,
interests: person.interests.concat({ en: 'Test', es: 'Test' })
};
}
return person;
});
const newState = {
...colleagues,
persons: updatedPersons
};
3)
const updatedPersons = colleagues.persons.map(person => {
if(person.id === personId) {
return {
...person,
[key]: value
};
}
return person;
});
// create a copy of the state
const newState = {
...colleagues,
persons: updatedPersons
};
4) ОК
Комментарии:
1. Спасибо за ваш ответ. Я добавил еще один пример к своему сообщению. Подходы, которые вы предоставили, например, 2 и 3, заставляют меня обновлять весь
persons array
, даже если изменения применимы только к конкретному пользователю. Это правильный путь? Или есть способ получше? Поскольку другиеpersons
не подвергаются манипуляциям, я предполагаю, что они не мутировали, и эти объекты не нужно применять как новый объект. Или я должен на самом делеreturn { ...person}
убедиться, или это не имеет смысла?2. @entiendoNull, Вы не обновляете массив. При использовании map создается новый массив. Важный момент в том, что вам не нужно создавать совершенно новое состояние, вам нужно создавать новые экземпляры только для объектов, которые вы собираетесь обновлять.
Ответ №2:
для первого я бы сделал так,
const newState = {
...colleagues,
persons: [...persons, newColleague]
};