Ответ 1
EDIT:
Явно отвечая на ваш первый вопрос, если ваши редукторы правильно построены, ваше дерево состояний должно инициализироваться абсолютно без данных. Но должна быть правильная форма. Ваши редукторы всегда должны иметь возвращаемое значение по умолчанию - при рендеринге стороны сервера - Redux должен отображать только начальное состояние
После рендеринга на стороне сервера, когда хранилище (то есть клиентская сторона) нуждается в обновлении из-за действия пользователя, ваша форма состояния для всех ваших данных продукта уже существует (это просто, что некоторые из них, вероятно, будут по умолчанию значения.). Вместо того, чтобы переписывать объект, ваше просто заполнение пробелов, так сказать.
Предположим, что в вашем представлении второго уровня вам нужны name
, photo_url
, price
и brand
, а в исходном представлении есть 4 продукта, ваш рендер-магазин будет выглядеть примерно так:
{
products: {
by_id: {
"1": {
id: "1",
name: "Cool Product",
tags: [],
brand: "Nike",
price: 1.99,
photo_url: "http://url.com",
category: "",
product_state: 0,
is_fetching: 0,
etc: ""
},
"2": {
id: "2",
name: "Another Cool Product",
tags: [],
brand: "Adidas",
price: 3.99,
photo_url: "http://url2.com",
category: "",
product_state: 0,
is_fetching: 0,
etc: ""
},
"3": {
id: "3",
name: "Crappy Product",
tags: [],
brand: "Badidas",
price: 0.99,
photo_url: "http://urlbad.com",
category: "",
product_state: 0,
is_fetching: 0,
etc: ""
},
"4": {
id: "4",
name: "Expensive product",
tags: [],
brand: "Rolex",
price: 199.99,
photo_url: "http://url4.com",
category: "",
product_state: 0,
is_fetching: 0,
etc: ""
}
},
all_ids: ["1", "2", "3", "4"]
}
}
В приведенных выше данных вы можете видеть, что некоторые ключи - это просто пустые строки или пустой массив. Но у нас есть наши данные, необходимые для фактического первоначального рендеринга страницы.
Затем мы могли бы сделать асинхронные вызовы на клиенте в фоновом режиме сразу после рендеринга сервера, и документ готов, вероятность того, что сервер вернет эти начальные вызовы, прежде чем пользователь попытается получить данные в любом случае. Затем мы можем загружать последующие продукты по запросу пользователя. Я не думаю, что подход лучший, но это тот, который имеет для меня наибольший смысл. У некоторых других людей могут быть другие идеи. Это полностью зависит от вашего приложения и прецедента.
Я бы оставил только один объект продукта в состоянии и сохранял ВСЕ данные, относящиеся к продуктам.
Недавно я развернул приложение в производство, и я поделюсь некоторыми своими понимание. Приложение, не будучи слишком большим по размеру, было сложным структуры данных и прошел весь процесс как новичок к Редуксу в производстве (и имея руководство от моего архитектора) - Эти некоторые из наших выводов. Там нет правильного пути с точки зрения архитектуры, но, безусловно, есть некоторые вещи, которые следует избегать или делать.
1. Перед тем, как начать записывать редукторы, создайте "статическое" состояние
Если вы не знаете, куда идете, вы не можете добраться туда. Написание всей структуры вашего состояния вне квартиры поможет вам понять, как ваше состояние со временем изменится. Мы обнаружили, что это спасло нам время, потому что нам не нужно было переписывать большие разделы.
2. Проектирование состояния
держите его просто. Весь смысл Redux - упростить управление государством. Мы использовали множество советов из egghead.io tutorials о Redux, которые были созданы Дэн Абрамовым. Они ясны, действительно помогли решить множество проблем, с которыми мы столкнулись. я уверен, что вы читаете документы о нормализации состояния, но простые примеры, которые они дали, фактически переносились в большинстве моделей данных, которые мы реализовали.
Вместо того, чтобы создавать сложные веб-данные данных , каждый кусок данных содержал только собственные данные, если ему нужно было ссылаться на другую часть данных , на которые он ссылался только на id. нашел, что этот простой шаблон охватывает большинство наших потребностей.
{
products: {
by_id: {
"1": {
id: "1",
name: "Cool Product",
tags: ["tag1", "tag2"],
product_state: 0,
is_fetching: 0,
etc: "etc"
}
},
all_ids: ["1"]
}
}
В приведенном выше примере тегами может быть другой фрагмент данных с аналогичной структурой данных с использованием by_id
и all_ids
. Всюду по документам и тету, Абрамов продолжает ссылаться на реляционные данные и реляционные базы данных, это действительно было для нас ключом. Сначала мы продолжали смотреть на пользовательский интерфейс и конструировать наше государство вокруг того, как мы думали, что мы его покажем. Когда это было нажато, и мы начали группировать данные на основе этого отношения к другим частям данных, все начало защелкнуться.
Быстро перевернувшись на ваш вопрос, я бы избегал дублирования любых данных, как уже упоминалось в другом комментарии, лично я просто создаю ключ в объекте состояния с именем product_modal
. пусть модальные позаботятся о своем собственном состоянии...
{
products: {
...
},
product_modal: {
current_product_id: "1",
is_fetching: true,
is_open: true
}
}
Мы обнаружили, что следующий шаблон с состоянием страницы тоже очень хорошо работает... мы просто рассматривали его как любую другую часть данных с id/name и т.д.
3. Редукционная логика
убедитесь, что редукторы отслеживают свое состояние, многие из наших редукторов выглядели довольно похожими, сначала это чувствовало себя как СУХОЙ ад, но потом мы быстро поняли силу более редукторов... скажем, что действие отправлено, и вы хотите обновить целый кусок состояния. в вашем редукторе для действия и вернуть новое состояние. Если вы хотите обновить одно или два поля в одном состоянии... тогда вы просто сделаете то же самое, но только в полях, которые хотите изменить. большинство наших редукторов были просто оператором switch с случайным вложенным оператором if.
Объединение редукторов
Мы не использовали combReducers, мы писали наши собственные. Это было не сложно, это помогло нам понять, что происходило в Редуксе, и это позволило нам немного поучиться нашему государству. Это было бесценно
Действия
Middleware - ваш друг... мы использовали API-интерфейс fetch с redux-thunk, чтобы сделать запросы RESTful. Мы разделили требуемые запросы данных на отдельные действия, которые назывались store.dispatch() для каждого фрагмента данных, для которого требуется обновление для вызова. Каждая отправка отправила другое действие для обновления состояния. Это помогло обновить наше состояние модульно и позволило нам обновлять большие разделы или по мере необходимости подробно.
Работа с API
Хорошо, так что здесь слишком много, чтобы иметь дело с этим. Я не говорю, что наш путь - лучший... но он сработал для нас. Сокращение... у нас есть внутренний API в Java с публично открытыми конечными точками. Вызовы из этого API не всегда легко отображались на лицевой стороне. Мы этого не реализовали, но в идеале исходная конечная точка init
могла быть написана на их конце, чтобы получить кучу исходных данных, которые необходимы для того, чтобы ускорить перемещение по переднему концу.
Мы создали публичный API на том же сервере, что и приложение, написанное на PHP. Этот API абстрагировал внутренние конечные точки API (а в некоторых случаях и данные) от внешнего интерфейса и браузера.
Когда приложение выполнит запрос GET на /api/projects/all
, PHP API затем вызовет наш внутренний API, получит необходимые данные (иногда по нескольким запросам) и вернет эти данные в удобном для использования формате, который может использовать сокращение.
Это может быть не идеальный подход для приложения javascript, но у нас не было возможности создать новую внутреннюю структуру API, нам нужно было использовать тот, который существует уже несколько лет, мы нашли приемлемую производительность.