#javascript #arrays #json #reactjs #redux
#javascript #массивы #json #reactjs #redux
Вопрос:
У меня есть простой массив данных JSON, который выглядит следующим образом (он такой же в моем хранилище Redux, и я храню его под properties
):
[
{
"id": "room",
"name": "Room",
"description": "Just a room",
"foo": "bar",
},
{
"id": "apartment",
"name": "Apartment",
"description": "just an apartment",
"foo": "bar",
}
]
Это должен быть массив, потому что я сопоставляю его:
{properties.map(property =>
<Property
id={property.id}
name={property.name}
description={property.description}
foo={property.foo}
/>)}
Таким образом, у меня есть два свойства, отображаемые в моем приложении.
Вопрос в том, как мне обновить "foo"
в Redux?
Этот мой редуктор в настоящее время написан в соответствии с документами:
case 'UPDATE_FOO':
return {
...state,
properties: {
...state.properties,
[action.id]: {
...state.properties[action.id],
foo: action.fooData,
}
}
}
Конечно, он выдает TypeError: Cannot read property 'room' of undefined
, потому что я пытаюсь получить доступ state.properties["room"]
, а этого не существует.
Я думал о том, чтобы изменить форму моего хранилища JSON и Redux, но как только я меняю его на именованные объекты, я не могу сопоставить его…
Спасибо!
Ответ №1:
Измените свое хранилище на объект и сгенерируйте массив, когда вам нужно его отобразить, преобразовав его в массив, используя Object.values()
:
{Object.values(properties).map(property => (
<Property key={property.id} {...property} />
)}
Если порядок может измениться (например, сортировка), вам необходимо иметь другой массив с идентификаторами для хранения порядка (см. redux normalized state).:
{
properties: {
room: {
"id": "room",
"name": "Room",
"description": "Just a room",
"foo": "bar",
},
apartment: {
"id": "apartment",
"name": "Apartment",
"description": "just an apartment",
"foo": "bar",
}
}
}
{
properties: {
room: {
"id": "room",
"name": "Room",
"description": "Just a room",
"foo": "bar",
},
apartment: {
"id": "apartment",
"name": "Apartment",
"description": "just an apartment",
"foo": "bar",
}
},
order: ['apartment', 'room']
}
{order.map(id => (
<Property key={id} {...properties[id]} />
)}
Комментарии:
1. Может быть, стоит указать, что рендеринг
Property
может быть сокращен доObject.values(properties).map(property => <Property key={property.id} {...property}/>)
2. Мне очень нравится ваш ответ, но настройка хранилища с помощью JSON в формате, подобном этому:
const initialState = { myJsonData}
закончится тем, чтоstate.properties.properties
и это добавит еще один уровень к моему редуктору, я прав? 🙁3. Нет — это просто
state.properties
. Массивproperties
заменяется объектомproperties
.4. @OriDrori хм, тогда я, должно быть, делаю что-то не так, но я думаю, что «свойства» перетаскиваются сюда из файла JSON: imgur.com/a/FECwFCq . Не имеет значения, инициализирую ли я хранилище с
const initialState = {properties: myJsonData}
помощью orconst initialState = {myJsonData}
, я всегда получаю его в два раза: [5. Вам нужно будет нормализовать JSON при его вставке, что означает, что вам нужно будет повторить его и создать форму состояния в редукторе.
Ответ №2:
Если вы хотите обновить хранилище, используя только идентификатор. Вы можете найти один элемент (который вы пытаетесь отредактировать) в массиве свойств, используя идентификатор, а затем обновить его:
case 'UPDATE_FOO':
const newProperties = state.properties.map(property => {
if(property.id === action.id) {
return { ...property, foo: action.fooData}
}
return property;
})
return {
...state,
properties: newProperties
}
}
Комментарии:
1. Это здорово, но так сложно читать и понимать: (Я думаю, я должен пойти с immer, по крайней мере, тогда? Это плоский JSON, и все еще обновление prop выглядит так безумно.