Автор оригинала: Emmanuel Ohans.
Это всеобъемлющее (но упрощенное) руководство для абсолютных новичков Redux или любой, кто хочет переоценить их понимание фундаментальных концепций Redux.
Для расширенного Оглавление Пожалуйста, Посетите эту ссылку , и для большего количества Расширенный redux Концепции Проверьте мой Redux книги Отказ
Вступление
Эта статья (которая на самом деле книга) – это отсутствующая штука, если вы долго искали, как освоить Redux.
Прежде чем начать, я должен сказать вам, что книга в первую очередь обо мне. Да я. Моя борется с обучением Redux и ищете лучший способ научить его.
Несколько лет назад я только что научился реагировать. Я был взволнован этим, но, опять же, все остальные, казалось, говорили о чем-то другом, называемом redux.
Гоша! Обучающая полоса когда-либо заканчивается?
Как инженер, совершенный к моему личному развитию, я хотел быть в знании. Я не хотел быть оставленным. Итак, я начал учиться Redux.
Я проверил документацию Redux. Это было довольно хорошо, на самом деле! По какой-то причине он просто не совсем щелкнул для меня. Я также проверил кучу видео YouTube. Те, которые я нашел, просто казалось, бросился и не подробно. Плохо меня.
Честно говоря, я не думаю, что видеоуправления я наблюдал, были плохими. Было просто что-то отсутствует. Легкое руководство, которое было хорошо продумано и написано для здравого человека, как я, а не для воображаемого гуманоида.
Оказалось, я не был один.
Мой друг, кто-то, кого я наставнил в то время, только что завершил курс сертификации разработчика RACT, в котором он заплатил большие баксы (более 300 долларов), чтобы получить сертификат.
Когда я попросил его честные отзывы о программе, его слова были вдоль линий:
Видите ли, здесь многое, как мой друг, все пытается понять Redux. Они, возможно, используют Redux, но они не могут сказать, что они действительно понимают, как это работает.
Я решил найти решение. Я собирался глубоко понимать redux и найти более четкий способ научить его.
То, что вы собираетесь читать, взяли месяцы обучения, а затем еще больше времени писать и построить пример проекты, сохраняя ежедневную работу и другие серьезные обязательства.
Но вы знаете, что?
Я очень взволнован, чтобы поделиться этим с вами!
Если вы искали руководство Redux, которое не будет говорить по своей голове, это так. Не смотрите дальше.
Я принял во внимание мою борьбу и тех из многих других, которых я знаю. Я обязательно научу вас важному – и сделать это, не заставляя вас смущены.
Теперь это обещание.
Мой подход к преподаванию redux
Настоящая проблема с преподаванием Redux – особенно для начинающих – не сложность сама библиотеки Redux.
Я не думаю, что это так. Это всего лишь крошечная 2КБ библиотека – включая зависимости.
Посмотрите на сообщество Redux в качестве новичка, и вы будете быстро потерять свой разум. Есть не Просто Redux, но целое много других предполагаемых «связанных библиотек» необходимо для создания приложений реального мира.
Если вы потратили некоторое время, делая немного исследования, то вы уже встречались с ними. Там redux, red-redux, redux-thunk, redux-saga, redux-promise, повторно, пересматривают и многое другое!
Как будто этого недостаточно, есть также некоторая маршрутизация, аутентификация, серверная сторона, тестирование, тестирование и пакет, посыпанный на нем – все сразу.
Гоша! Это подавляющее.
«Учебник Redux» часто не так много о redux, но все остальные вещи, которые поставляются с ним.
Должен быть более вменяемый подход, адаптированный к начинающим. Если вы разработчик гуманоида, у вас, безусловно, не было бы проблем с этим. Угадай, что? Большинство из нас на самом деле люди.
Итак, вот мой подход к преподаванию Redux.
Забудьте о всех дополнительных вещах и давайте просто сделаем Redux. Ага!
Я имею только введен только как минимум Barest Minment. Там не будет реагированного маршрутизатора, Redux-формы, повторного повторного, AJAX, WebPack, аутентификации, тестирования, ни одного из них – на данный момент!
И угадай что? Вот как вы научились делать некоторые важные жизненные навыки «У тебя есть.
Как вы научились ходить?
Вы начали бегать за один день? Нет!
Позвольте мне пройтись через здравый подход к обучению redux – без проблем.
Плотно держаться.
«Поднимающийся прилив поднимает все лодки»
Как только вы получите повешение о том, как основы Redux работает (поднимающий прилив), все остальное будет легче рассуждать о (поднимает все лодки).
Примечание на кривой обучения redux
У Редукса есть кривая обучения. Я не говорю иначе.
Обучение прогулке также имела к ней кривую обучения. Однако с систематическим подходом к обучению вы преодолеете это.
Вы упали несколько раз, но это было в порядке. Кто-то всегда был рядом, чтобы удержать тебя, и помочь вам встать на ноги.
Ну, я надеюсь быть таким человеком для вас – как вы учитесь Redux со мной.
Что вы узнаете
Ведь сказано и сделано, вы поймете, что redux не так страшно, как кажется снаружи.
Основные принципы так дарны легко!
Во-первых, я научу вам основы Redux в простые, легко приближающуюся к языку.
Затем мы построим несколько простых приложений. Начиная с Basic Hello World App.
Но это не хватает.
Я включаю упражнения и проблемы, я думаю, что вы должны также решать.
Эффективное обучение не только для чтения и слушания. Эффективное обучение в основном о практике!
Подумайте об этом как на домашнее задание, но без сердитого учителя. Практикуя упражнения, вы можете Tweet Мне с хэштегом #underStandingressux и я определенно посмотрю!
Нет злых учителей, а?
Упражнения хорошие, но вам также нужно смотреть, как я построить большее приложение. Это где мы охватываем вещи построению Skypey , приложение сладкого обмена сообщениями вроде как клон Skype.
Получили функции Skyyey, такие как редактирование сообщений, удаление сообщений и отправка сообщений нескольким контактам.
Ура!
Если бы это не взволновало, я не знаю, что будет. Я супер взволнован, чтобы показать вам это!
Предварительное условие
Единственная предпосылка в том, что вы уже знаете реагировать. Если вы этого не сделаете, Дейв Кеддия ‘s Чистый реагировать Является ли моя личная рекомендация, если у вас есть несколько долларов, чтобы посмотреть. Я нет партнера. Это просто хороший ресурс.
Скачать PDF & EPUB для записи в автономном режиме
Видео ниже подчеркивает процесс, участвующий в получении ваших версий PDF и EPUB из книги.
Суть это:
- Посетите Страница продаж книги Отказ
- Используйте купон FreeCodecamp Чтобы получить 100% скидка на цену, так что вы получите книгу за 29 долларов за 0 долларов.
- Если вы хотите сказать, спасибо, пожалуйста, порекомендуйте эту статью, разделяя его в социальных сетях.
Теперь давайте начнем.
Глава 1: узнать Redux
Некоторые годы назад, разрабатывающие фронт-конечные приложения казались шутки многими. В наши дни растущая сложность строительства достойных фронт-конечных приложений почти подавляет.
Кажется, что для удовлетворения прессования требований постоянно-требовательного пользователя нежный милый кот заросший границы дома. Это становится бесстрашным львом с 3-дюймовыми когтями и рот, который открывается достаточно широким, чтобы соответствовать человеческой голове.
Да, это то, что современное фронт-концевое развитие чувствует себя как в эти дни.
Современные рамки, такие как угловые, реагирование и Vue, сделали большую работу при укровении этого «зверя». Аналогичным образом, современные философии, такие как принудительные redux, также существуют, чтобы дать этот «зверь» холода.
Следуйте, как мы посмотрим на эти философии.
Что такое redux?
Официальная документация для Redux READS:
Эти 9 слов были похоже на 90 неполных фраз, когда я впервые прочитал их. Я просто не понял. Вы, скорее всего, тоже не тоже.
Не потеть это. Я пойду через это немного, и как вы используете Redux больше, это предложение станет более четкой.
На светлой стороне, если вы прочитаете документацию немного дольше, вы найдете более пояснительные вещи где-то там.
Это читает:
Ты видишь это?
В условиях Лэй-мужчины, это говорит: «Это поможет вам приручить зверь» Отказ Метафорически.
Redux убирает некоторых хлопот, столкнувшихся с государственным управлением в крупных приложениях. Он предоставляет вам отличный опыт разработчика, и гарантирует, что жизнеспособность вашего приложения не жертвует для любого из них.
При разработке приложений RACT, вы можете обнаружить, что сохранение всего вашего состояния в компоненте верхнего уровня больше не достаточно для вас.
Вы также можете иметь много данных, изменяющихся в вашем приложении со временем.
Redux помогает решить такие проблемы. Уменьшите вам, это не единственное решение там.
Зачем использовать redux?
Как вы уже знаете, вопросы, такие как «Почему вы должны использовать более B?» сводится к вашим личным предпочтениям.
Я создал приложения в производстве, которые не используют Redux. Я уверен, что многие сделали то же самое.
Для меня я беспокоился о внесении дополнительного слоя сложности для членов моей команды. В случае, если вам интересно, я не жалею о решении вообще.
Автор Redux, Дэн Абамов , также предупреждает о опасности внедрения redux Слишком рано в ваше приложение. Вы не можете понравиться Redux, и это достаточно честно. У меня есть друзья, которые этого не делают.
Это сказано, что все еще есть очень приличные причины для изучения redux.
Например, в более крупных приложениях с множеством движущихся частей, государственное управление становится огромной проблемой. Redux Ticks это довольно хорошо, без проблем с производительностью или торговля оправданием.
Еще одна причина, которую многие разработчики любят Redux – это опыт разработчика, который поставляется с ним. Многие другие инструменты начали делать подобные вещи, но и большие кредиты для redux.
Некоторые из хороших вещей, которые вы получаете с использованием Redux, включают в себя журнал, горячую перезагрузку, время путешествий, универсальные приложения, записи и воспроизведения – все, не делая так много на вашем конце, как разработчик. Эти вещи, скорее всего, будут звучать вообразить, пока вы не используете их и не смогу себе.
Разговор Дэн под названием Горячая перегрузка со временем путешествия даст вам хорошее чувство того, как эти работы.
Также Mark Ericsson , один из сопровождающих Redux, говорит, что Более 60% Реактивных приложений в производстве используют Redux. Это много!
Следовательно, и это только моя мысль, многие инженеры любят показывать потенциальных работодателей, которые они могут поддерживать более крупные производственные кодовые базы, встроенные в React и Redux, поэтому они изучают Redux.
Если вы хотите еще несколько причин использовать Redux, DAN, Creator redux, есть еще несколько причин, подчеркнутых в Его статья на среднем.
Если вы не считаете себя старшим инженером, советую вам выучить Redux – во многом из-за некоторых принципов он учит. Вы узнаете новые способы выполнения общих вещей, и это, скорее всего, сделает вас лучшим инженером.
У каждого есть разные причины для подбора разных технологий. В конце концов, звонок твой. Но это определенно не повредит, чтобы добавить Redux на ваш набор навыков.
Объясняя Redux до 5 лет
Этот раздел книги действительно важен. Объяснение здесь будет ссылаться на книгу. Так что будьте готовы.
Поскольку 5-летний не имеет времени для технического жаргона, я сохраню это очень простое, но отношение к нашей цели обучения Redux.
Итак, вот мы идем!
Давайте рассмотрим событие, с которым вы, вероятно, знакомы – отправляетесь в банк для снятия наличных. Даже если вы не делаете это часто, вы, вероятно, знаете, как выглядит процесс.
Вы просыпаетесь однажды утром, и отправляйтесь в банк как можно быстрее. Идя в банк, есть только один намерение/действие Вы имели в виду: до СНЯТЬ ДЕНЬГИ СО СЧЕТА.
Вы хотите снять деньги из банка.
Вот где все интересны.
Когда вы попадаете в банк, вы тогда переходите прямо к кассу, чтобы сделать ваш запрос известен.
Подожди, вы пошли на кассир?
Почему ты не просто пошел в банковское хранилище, чтобы получить ваши деньги?
В конце концов, это твои тяжелые заработанные деньги.
Ну, как вы уже знаете, все не работают таким образом. Да, у банка есть деньги в хранилище, но вы должны поговорить с кассу, чтобы помочь вам выполнить должное процедуру для ухода за ваши собственные деньги.
Кассир, с их компьютера, затем входит в некоторые команды и предоставляет вам ваши деньги. Очень просто.
Теперь, как Redux вписывается в эту историю?
Мы скоро доберемся до подробной информации, но сначала терминология.
1. Банк хранилище в банке, что Redux Store это redux.
Банковское хранилище держит деньги в банке, верно?
Ну, в вашем приложении, вы не тратите деньги. Вместо этого Государство вашего приложения похоже на деньги, которые вы проводите. Весь пользовательский интерфейс вашего приложения является функцией вашего состояния.
Также как банка хранится в безопасности ваших денег в банке, состояние вашего заявления сохраняется в безопасности чем-то, называемым магазин Отказ Итак, магазин сохраняет ваши «деньги» или Государство нетронутый.
Тебе нужно вспомнить это, хорошо?
Магазин Redux можно сравнить в банковском хранилище. Он содержит состояние вашего приложения – и сохраняет его в безопасности.
Это приводит к первому принципу redux:
Не позволяйте словаму спутать вас.
В простых терминах, с redux, рекомендуется сохранить состояние приложения в одном объекте, управляемом redux магазин Отказ Это как иметь один хранилище В отличие от мусорных денег везде вдоль банка.
2. Перейдите в банк с Действие в уме.
Если вы собираетесь получить какие-либо деньги из банка, вам придется войти с некоторыми намерениями или действиями, чтобы снять деньги.
Если вы просто идете в банк и бродить, никто не собирается просто дать вам деньги. Вы можете даже заканчиваться безопасностью. Грустные вещи.
То же самое можно сказать же для redux.
Напишите как можно больше кода, но если вы хотите обновить состояние вашего приложения Redux (как вы делаете с SetState в React) вам нужно позволить Redux знать об этом с Действие Отказ
Таким же образом вы следуете надлежащим образом, чтобы вывести свои собственные деньги из банка, Redux также учитывает должное процедуру для изменения/обновления состояния вашего приложения.
Теперь это приводит к принципу Redux # 2.
Что это значит на простых языках?
Когда вы идете в банк, вы идете туда с учетом ясных действий. В этом примере вы хотите отозвать немного денег.
Если мы решили представить этот процесс в простом приложении Redux, ваше действие в банк может быть представлено объектом.
Тот, который выглядит так:
{
type: "WITHDRAW_MONEY",
amount: "$10,000"
}В контексте приложения Redux этот объект называется Действие Действительно У него всегда есть Тип поле, которое описывает действие, которое вы хотите выполнить. В этом случае это СНЯТЬ ДЕНЬГИ СО СЧЕТА.
Всякий раз, когда вам нужно изменить/обновить состояние вашего приложения Redux, вам нужно отправить действие.
Не стресс, как это сделать. Я только укладываю здесь основы. Мы скоро вними в много примеров.
3. Кассир в банке, что Редуктор это redux.
Хорошо, сделайте шаг назад.
Помните, что в истории выше, вы не могли просто пойти прямо в банкнот, чтобы получить ваши деньги из банка. Нет. Вы должны были сначала увидеть кассир.
Ну, у вас имею в виду акцию, но вам пришлось передать это действие кому-то – кассир – кто в свою очередь общался (по каким по-прежнему они делали) с хранилищем, который держит все деньги банка.
То же самое можно сказать же для redux.
Как вы сделали свои действия, известные кассиру, вы должны сделать то же самое в вашем приложении Redux. Если вы хотите обновить состояние вашего приложения, вы передаете свой Действие к Редуктор – Наш кассир.
Этот процесс в основном называется диспетчером Действие Отказ
Отправка – это просто английское слово. В этом примере и в мире redux оно используется для того, чтобы означать отпуск от действия редукторов.
Редуктор Знает что делать. В этом примере это примет ваши действия на Roy_money и убедитесь, что вы получите свои деньги.
В условиях redux деньги, которые вы тратите, это ваша Государство Отказ Итак, ваш редуктор знает, что делать, и это всегда возвращает ваш Новое состояние Отказ
Хм. Это было не так трудно понять, верно?
И это приводит к последнему принципу Redux:
Как мы продолжаем, я объясню, что означает «чистый» редуктор. На данный момент, что важно понять, что для обновления состояния вашего приложения (как вы делаете с SetState в React,) Ваши действия всегда должны быть отправлены (отправлены) для редукторов, чтобы получить ваш Новое состояние Отказ
С этой аналогией вы должны иметь представление о том, что являются наиболее важными актерами redux: магазин , Редуктор и Действие Отказ
Эти три актера являются ключевыми для любого приложения Redux. Как только вы понимаете, как они работают, основная часть этого дела сделана.
Глава 2: Ваше первое приложение Redux
Несмотря на то, что я провел достаточно времени, объясняя принципы Redux так, как вы не забудете, устные инструкции имеют свои пределы.
Чтобы углубить ваше понимание принципов, я покажу вам пример. Ваше первое приложение Redux, если вы хотите назвать это так.
Мой подход к преподаванию – ввести примеры растущей трудности. Таким образом, для начала этот пример ориентирован на рефакторинг простого чистого приложения RACT для использования redux.
Целью здесь состоит в том, чтобы понять, как ввести redux в простом проекте реагирования и углубляется ваше понимание фундаментальных концепций Redux.
Готовый?
Ниже приведено тривиальное приложение «Hello World», с которыми мы будем работать.
Не смейтесь.
Вы научитесь согнуть мышцы Redux из «известной» концепции, такие как реагирование, к «неизвестному» Redux.
Структура реакции Hello World Application
Приложение React мы будем работать с загрузкой с Create-React-App Отказ Таким образом, структура приложения, к которой вы уже привыкли.
Вы можете схватить репо из Github Если вы хотите следовать, которые я рекомендую.
Там есть index.js Входной файл, который отображает <Приложение/> Компонент к Дом Отказ
Главная Приложение Компонент состоит из определенного компонент.
Это Компонент берет в Tech PROP, и этот опоры отвечает за конкретную технологию, отображаемую пользователю.
Например, даст следующее:
Кроме того, даст следующее.
Теперь вы получаете суть.
Вот что Приложение Компонент выглядит как:
src/app.js.
import React, { Component } from "react";
import HelloWorld from "./HelloWorld";
class App extends Component {
state = {
tech : "React"
}
render() {
return
}
}
export default App; Хорошо посмотреть на Государство объект.
Есть только одно поле, Tech , в Государство объект, и это передано как опора в HellowOrld Компонент, как показано ниже:
Не беспокойтесь о реализации HellowOrld Компонент – пока. Это просто берет в себя Tech опоры и применяет некоторые модные CSS. Вот и все.
Поскольку это сосредоточено в основном на Redux, я пропущу детали укладки.
Итак, вот вызов.
Как мы рефикторуем наше Приложение использовать Redux ?
Как мы забраем государственный объект и имеем его полностью управлять redux? Помните, что redux – это Государственный менеджер для вашего приложения.
Давайте начнем отвечать на эти вопросы в следующем разделе.
Пересмотр ваших знаний о redux
Помните цитату из официальных документов?
Одна ключевая фраза в вышеуказанном предложении – Государственный контейнер Отказ
Технически, вы хотите Государство вашего приложения, чтобы управлять Redux.
Это то, что делает redux a Государственный контейнер Отказ
Ваше состояние React Component все еще существует. Redux не забирает его.
Тем не менее, Redux будет эффективно управлять вашим В целом состояние приложения. Как банка хранилище, у него есть магазин сделать это.
Для простого <Приложение/> Компонент у нас здесь, государственный объект прост.
Вот:
{
tech: "React"
}Нам нужно взять это из <Приложение/> Состояние компонента, и у него управляется redux.
Из моего предыдущего объяснения вы должны помнить аналогию между Bank Vault и Store Redux. Банковское хранилище держит деньги, redux магазин Сохраняет объект состояния приложения.
Итак, каков первый шаг к рефакторию <Приложение/> Компонент для использования redux?
Да, вы поняли это правильно.
Удалите состояние компонента изнутри <Приложение/> Отказ
Redux магазин Будет ответственность за управление приложением Государство Отказ С этим говорим, нам нужно удалить текущий объект состояния из Приложение/>.
import React, { Component } from "react";
import HelloWorld from "./HelloWorld";
class App extends Component {
// the state object has been removed.
render() {
return
}
}
export default App; Раствор выше является неполным, но сейчас, <Приложение/> не имеет государства.
Пожалуйста, установите Redux, запустив пряжа Добавить redux из интерфейса командной строки (CLI). Нам нужны redux пакет делать что-либо правильно.
Создание магазина Redux
Если <Приложение/> Не будет управлять этим государством, тогда мы должны создать магазин Redux для управления состоянием приложения.
Для банковского хранилища пару механические инженеры, вероятно, были наняты для создания безопасного обслуживания денег.
Чтобы создать управляемый государственный объект для нашего приложения, нам не нужны механические инженеры. Мы сделаем это программно, используя некоторые API-APIS Redux Reartments к нам.
Вот какой код для создания redux магазин похоже:
import { createStore } from "redux"; //an import from the redux library
const store = createStore(); // an incomplete solution - for now.Сначала мы импортируем Createstore Функция завода из Redux. Тогда мы вызываем функцию, Createstore () создать магазин.
Теперь Createstore Функция принимает несколько аргументов. Первый – это Редуктор.
Итак, более полное создание магазина будет представлено так: Createstore (Редуктор)
Теперь позвольте мне объяснить, почему у нас есть Редуктор там.
Отношения в магазине и редуктора
Вернуться к аналогии банка.
Когда вы идете в банк, чтобы вывести снятие, вы встретитесь с кассиром. После того, как вы сделаете ваш Снять деньги Намерение/действие, известное кассиру, они не просто передают вам запрошенные деньги.
Нет.
Кассир сначала подтверждает, что у вас достаточно денег на вашем счете, чтобы выполнить операцию снятия снятия, которую вы ищете.
Кассир сначала гарантирует, что у вас есть деньги, которые вы говорите, что вы делаете.
С компьютера они могут видеть все такое общения с хранилищем, так как хранилище держит все деньги в банке.
В двух словах кассир и хранилище всегда в синхронизации. Отличные приятели!
То же самое можно сказать же для redux Магазин (наше собственное хранилище,) и redux Редуктор (наш собственный касмир)
Магазин и редуктор – отличные приятели. Всегда в синхронизации.
Почему?
Редуктор Всегда «разговаривает» к Магазин Отказ Также как кассир остается в синхронизации с хранилищем.
Это объясняет, почему создание магазина необходимо вызвать с Редуктор и это обязательно. Редуктор это единственный обязательный аргумент, переданный в Createstore ()
В следующем разделе у нас будет краткий взгляд на редукторы, а затем создать Магазин Проходя Редуктор в Createstore Заводская функция.
Редуктор
Мы скоро пойдем в более подробные детали, но я буду держать это коротко сейчас.
Когда вы слышите слово, редуктор, что приходит на ум?
Уменьшать?
Да, это то, что я думал.
Похоже, как уменьшить.
Ну, согласно официальному redux Документы :
Наш кассир – довольно важный человек, а?
Итак, в чем дело с редуктором. Что оно делает?
В более технических терминах редуктор также называется восстановительной функцией. Вы не можете заметить, но вы, наверное, уже используете редуктор – если вы знаете с Array.reduce () метод.
Вот быстрый переподготовка.
Рассмотрим код ниже.
Это популярный способ получить сумму значений в массиве JavaScript:
let arr = [1,2,3,4,5] let sum = arr.reduce((x,y) => x + y) console.log(sum) //15
Под капотом функция прошла в Arr.recuce называется Редуктор Отказ
В этом примере редуктор принимает два значения, а Аккумулятор и а CurrentValue , где х это Аккумулятор и y это текущая стоимость.
Таким же образом, редуктор Redux – это просто функция. Функция, которая принимает в Два Параметры. Первый, будучи Государство приложения, а другой – Действие Отказ
Боже мой! Но где Государство и Действие передается в Редуктор родом из?
Когда я изучал Redux, я спросил себя в этом вопросе несколько раз.
Во-первых, посмотрите на Array.reduce () Пример еще раз:
let arr = [1,2,3,4,5] let sum = arr.reduce((x,y) => x + y) console.log(sum) //15
Array.reduce Метод несет ответственность за прохождение в необходимых аргументах, х и y в аргумент функции, Редуктор Отказ Итак, аргументы не вышли из тонкого воздуха.
То же самое можно сказать же для redux.
Редуктор Redux также передается в определенный метод. Угадай, что это?
Ну вот!
createStore(reducer)
Createstore Заводская функция. Там немного больше участвует в процессе, как вы скоро посмотрите.
Как Array.reduce () , Createstore () несет ответственность за передачу аргументов в редуктор.
Если вы не боитесь техническими вещами, вот убранная версия реализации Createstore В пределах исходного кода Redux.
function createStore(reducer) {
var state;
var listeners = []
function getState() {
return state
}
function subscribe(listener) {
listeners.push(listener)
return unsubscribe() {
var index = listeners.indexOf(listener)
listeners.splice(index, 1)
}
}
function dispatch(action) {
state = reducer(state, action)
listeners.forEach(listener => listener())
}
dispatch({})
return { dispatch, subscribe, getState }
}Не берите себя, если вы не получите код выше. Что я действительно хочу указать, находится в пределах Отправка функция.
Обратите внимание, как Редуктор называется с Государство и действие
Со всеми, что говорится, самый минимальный код для создания redux магазин это:
import { createStore } from "redux";
const store = createStore(reducer); //this has been updated to include the created reducer.Возвращаясь к процессу рефакторинга
Давайте вернемся к рефакторирующему приложение «Hello World» для использования Redux.
Если я потерял вас в любой момент в предыдущем разделе, пожалуйста, прочитайте раздел еще раз, и я уверен, что это погрузится. Лучше все еще, вы можете Спросите меня вопрос.
Хорошо, так вот все, что у нас есть в этот момент:
import React, { Component } from "react";
import HelloWorld from "./HelloWorld";
import { createStore } from "redux";
const store = createStore(reducer);
class App extends Component {
render() {
return
}
}
export default App; Имеет смысл?
Возможно, вы заметили проблему с этим кодом. См. Линия 4.
Редуктор Функция передана в Createstore пока не существует.
Теперь нам нужно написать один. Редуктор – это просто функция, помните?
Создайте новый каталог под названием Редукторы и создать index.js файл там. По сути, наша функция редуктора будет на пути SRC/Редукторы/index.js Отказ
Сначала экспортируйте простую функцию в этом файле:
export default () => {
}Помните, что Редуктор принимает в два аргумента – как установлено ранее. Прямо сейчас мы будем касаться себя первым аргументом, ШТАТ
Поместите это в функцию, и у нас есть это:
export default (state) => {
}Неплохо.
Редуктор всегда что-то возвращает. В начальном Array.reduce () Пример редуктора, мы вернули сумма аккумулятора и текущего значения.
Для redux Редуктор Вы всегда возвращаете Новое состояние вашего приложения.
Позволь мне объяснить.
После того, как вы входите в банк и сделаете успешный вывод, текущая сумма денег, содержащихся в хранилище Банка, для вас, больше не совпадает. Теперь, если вы вышли 200 долларов, вы сейчас короткие 200 долларов. Баланс вашего счета – 200 долларов.
Опять же, кассир и хранилище остаются в синхронизации на том, сколько у вас сейчас.
Так же, как кассир, это именно то, как Редуктор работает.
Как кассир, Редуктор всегда возвращает Новое состояние вашего приложения. На случай, если что-то изменилось. Мы не хотим выдавать тот же баланс банка, хотя был выполнен действие снятия снятия.
Мы доберемся до внутренних органов, как изменить/обновить состояние позже. На данный момент слепой доверие придется достаточно.
Теперь, вернемся к проблеме под рукой.
Так как мы не беспокоились об изменении/обновлении государства в этот момент, мы будем держать Новое состояние Быть возвращенным как то же самое Государство прошел.
Вот представление этого в пределах Редуктор :
export default (state) => {
return state
}Если вы отправитесь в банк, не выполняя действия, ваш банковский баланс остается прежним, верно?
Так как мы не выполняем никаких Действие Или даже пропустить это в редуктор, мы просто будем Возвращение То же самое штат.
Второй аргумент Createstore
Когда вы посещаете кассир в банке, если вы спросили их на баланс вашего счета, они посмотрит на него и расскажут вам.
Но как?
Когда вы впервые создали учетную запись в своем банке, вы либо сделали это с некоторой суммой депозита или нет.
Давайте назовем это первоначальный депозит на ваш счет.
Вернуться к redux.
Точно так же, когда вы создаете redux Магазин (Наши собственные деньги хранения денег), есть возможность сделать это с первоначальным депозитом.
В условиях redux это называется инициация приложения.
Думать в коде, инициация прошел ли второй аргумент в Createstore Функциональный вызов.
const store = createStore(reducer, initialState);
Прежде чем делать какие-либо денежные средства Действие Если вы запросили баланс вашего банковского счета, первоначальный депозит всегда будет возвращен вам.
После этого, в любое время вы выполняете любой денежный день Действие Этот первоначальный депозит также будет обновлен.
Теперь то же самое касается Redux.
Объект, переданный как инициация похоже на первоначальный депозит в хранилище. Это инициация всегда будет возвращено как Государство приложения, если вы не обновите состояние, выполняя Действие Отказ
Теперь мы обновим приложение, чтобы пройти в Первоначальное состояние :
const initialState = { tech: "React " };
const store = createStore(reducer, initialState);Обратите внимание, как инициация это просто объект, и именно то, что мы имели в качестве состояния по умолчанию в приложении React React, прежде чем мы начали рефакторинг.
Теперь вот все код у нас есть в этот момент – с Редуктор также импортируется в Приложение.
App.js.
import React, { Component } from "react";
import HelloWorld from "./HelloWorld";
import reducer from "./reducers";
import { createStore } from "redux";
const initialState = { tech: "React " };
const store = createStore(reducer, initialState);
class App extends Component {
render() {
return
}
}
export default App; Редукторы/index.js.
export default state => {
return state
}Если вы кодируете и пытаетесь запустить приложение сейчас, вы получите ошибку. Почему?
Посмотрите на Tech пропал в Отказ Это все еще читает, this.state.tech Отказ
Там больше нет государственного объекта, привязанного к <Приложение/> так что это будет undefined Отказ
Давайте исправить это.
Решение довольно простое. Так как магазин Теперь управляет состоянием нашего приложения, это означает приложение Государство Объект должен быть получен из магазин Отказ Но как?
Всякий раз, когда вы создаете магазин с Createstore () Созданный магазин имеет три открытых метода.
Один из них – getstate () Отказ
В любой момент времени, вызывая Гутрите Метод на созданный магазин вернет текущее состояние вашего заявления.
В нашем случае Store.GetState () вернет объект {Tech: «Реагировать»} Так как это Первоначальное состояние Мы передали в Createstore () Метод, когда мы создали Магазин Отказ
Вы видите, как все это сейчас вместе?
Следовательно, Tech опоры будут переданы в как показано ниже:
App.js.
import React, { Component } from "react";
import HelloWorld from "./HelloWorld";
import { createStore } from "redux";
const initialState = { tech: "React " };
const store = createStore(reducer, initialState);
class App extends Component {
render() {
return
}
} Редукторы/Редуктор.js.
export default state => {
return state
}И это так! Вы только что узнали основные основы Redux и успешно поощряли простое приложение React App для использования redux.
Приложение React теперь имеет свое государство, управляемое Redux. Все, что нужно быть полученным из Государство Объект будет схвачен из магазин Как показано выше.
Надеюсь, вы поняли весь процесс рефакторинга.
Для более быстрого обзора, посмотрите на это Github diff Отказ
С проектом «Hello World» мы хорошо посмотрели на некоторые существенные концепции Redux. Несмотря на то, что это такой крошечный проект, он дает приличное основание для создания!
Возможна Гоща
В только что заключено Здравствуйте, мир Пример, возможное решение, которое вы, возможно, придумали для захвата Государство от магазин может выглядеть так:
class App extends Component {
state = store.getState();
render() {
return ;
}
}Что вы думаете? Будет ли эта работа?
Так же, как напоминание, следующие два способа являются правильными способами инициализации состояния реагирования.
(a)
class App extends Component {
constructor(props) {
super(props);
this.state = {}
}
}(b)
class App extends Component {
state = {}
}Итак, вернитесь к ответу на вопрос, да, решение будет работать совсем хорошо.
Store.GetState () будет схватить текущее состояние из redux Магазин Отказ
Тем не менее, назначение, countrain.getstate () присвоит государство, полученное от Redux для этого из <Приложение/> компонент.
По словам, оператор возврата от оказывать такие как будет действительным.
Обратите внимание, что это гласит this.state.tech не Store.getState (). Tech Отказ
Хотя это работает, это против идеальной философии redux.
Если в приложении вы сейчас запустите this.settate () Состояние приложения будет обновлено без помощи Redux.
Это механизм реагирования по умолчанию, и это не то, что вы хотите. Вы хотите Государство Управляется redux Магазин быть единственным источником истины.
Вы извлекаете ли вы состояние, как в Store.GetState () или обновление/изменение Государство (Как мы посмотрим позже), вы хотите, чтобы это было полностью управляться redux, а не setstate ().
Поскольку Redux управляет приложением Государство , все, что вам нужно сделать, это кормить Государство от redux Магазин как реквизит к любой необходимой компоненте.
Еще один большой вопрос, который вы, вероятно, спрашиваете себя: «Почему я должен был пройти весь этот стресс, чтобы у меня было управление состоянию моего приложения By redux?»
Редуктор, магазин, Createstore Blah, Blah, Blah …
Да, я понимаю.
Я тоже почувствовал этот путь.
Однако рассмотрим тот факт, что вы не просто идете в банк и не Следуйте должным образом для снятия собственных денег. Это ваши деньги, но вы должны следовать должным образом.
То же самое можно сказать же для redux.
Redux имеет свой собственный «процесс» для того, чтобы делать вещи. Мы должны научиться, как это работает – и эй, ты не очень не делаешь!
Заключение и резюме
Эта глава была захватывающей. Мы сосредоточились в основном на установлении приличного фундамента для более интересных вещей.
Вот несколько вещей, которые вы узнали в этой главе:
- Redux предсказуемый Государственный контейнер Для приложений JavaScript.
-
CreatestoreФункция завода из redux используется для создания reduxМагазинОтказ -
Редукторэто единственный обязательный аргумент, переданный вCreatestore () - А
Редукторэто просто функция. Функция, которая принимает в Два Параметры. Первый – этоГосударствоиз приложения, а другой –ДЕЙСТВИЕ. - А
Редукторвсегда возвращаетНовое состояниевашего приложения. - Начальное состояние вашего приложения
инициацияпрошел ли второй аргумент вCreatestoreФункциональный вызов. Store.GetState ()вернет текущее состояние вашего заявления. ГдеМагазинДопустимый reduxМагазинОтказ
Внесение упражнений
Пожалуйста, пожалуйста, пожалуйста, не пропустите упражнения. Особенно, если вы не уверены в своих навыках Redux и действительно хотите получить лучшее из этого руководства.
Итак, возьми свои шляпы Dev и напишите какой-нибудь код:)
Кроме того, если вы хотите, чтобы я дал вам отзыв о любом из ваших решений в любой момент времени, твитнуть на меня с хэштегом #OnderstandingRedux И я буду рад посмотреть. Я не обещаю добраться до каждого твита, но я обязательно попробую!
Как только вы получите упражнения, увидимся в следующем разделе.
Помните, что хороший способ прочитать длительный контент – разбить его в более короткие усваимые биты. Эти упражнения помогают вам сделать только что. Вы берете некоторое время, постарайтесь решить упражнения, то вы вернетесь к чтению. Это эффективный способ учиться.
Хотите увидеть мои решения для этих упражнений? Я включил решения для упражнений в книжной упаковке. Вы найдете инструкции о том, как получить сопроводительный код и решения для тренировок, как только вы загружаете (бесплатно) электронную книгу (PDF и EPUB).
Итак, вот упражнение для этого раздела.
Упражнение
(а) Refactor Приложение для пользовательских карт для использования redux
В сопроводительных файлах кода для книги вы найдете приложение для пользователя, написанное исключительно в реакции. Состояние приложения управляется через реакцию. Ваша задача – переместить состояние, чтобы управлять исключительно Redux.
Глава 3: Понимание обновлений состояния с действиями
Теперь, когда мы обсудили основополагающие концепции Redux, мы начнем делать некоторые интересные вещи.
В этой главе мы будем продолжать учиться, делая, когда я проводил вас через другой проект – подробно объясняя каждый процесс.
Итак, какой проект собирается работать в это время?
У меня идеальный.
Пожалуйста, рассмотрите макет ниже:
О, он выглядит так же, как предыдущий пример – но с несколькими изменениями. На этот раз мы учитываем действия пользователей. Когда мы нажимаем любую из кнопок, мы хотим обновить состояние приложения, как показано в GIF ниже:
Вот как это отличается от предыдущего примера. В этом сценарии пользователь выполняет определенные действия, которые влияют на состояние применения. В первом примере все, что мы сделали, было отображать начальное состояние приложения без учета пользователей.
Какое действие redux?
Когда вы входите в банк, кассир получает ваши действия, то есть ваше намерение прийти в банк. В нашем предыдущем примере это было All_money Отказ Единственный способ, которым деньги покидают банковское хранилище, если вы делаете свои действия или намерение, известные кассиру.
Теперь то же самое касается редуктора Redux.
В отличие от setState () В Pure React, единственным способом, которым вы обновляете состояние приложения Redux, заключается в том, что вы сделаете свое намерение, известное для редуктора.
Но как?
Отправляя действия!
В реальном мире вы знаете точное действие, которое вы хотите выполнить. Возможно, вы могли бы написать это на скольжение и передать его кассиру.
Это работает почти так же с redux. Единственная проблема, как вы описываете действие в приложении Redux? Определенно не говоря уже о прилавке или пишу его на скольжение.
Ну, есть хорошие новости.
Действие точно описано с простой объектом JavaScript. Ничего больше.
Есть только одна вещь, о которой нужно знать. Действие Должен иметь Тип поле. Это поле описывает намерение действия.
В банке рассказ, если мы должны были описать ваши действия в банк, это выглядело так:
{
type: "withdraw_money"
}Это все, правда.
Действие redux описано как простой объект.
Пожалуйста, посмотрите на действие выше.
Вы думаете только только Тип Поле точно описывает ваши предполагаемые действия, чтобы сделать вывод в банке?
Хм. Я так не думаю. Как насчет суммы денег, которую вы хотите уйти?
Много раз ваши действия понадобится дополнительные данные для полного описания. Рассмотрим действие ниже. Я утверждаю, что это делает более хорошо описанное действие.
{
type: "withdraw_money",
amount: "$4000"
}Теперь есть достаточная информация, описывающая действие. Ради примера игнорируйте все другие детали. Действие может включать в себя, например, номер вашего банковского счета.
Кроме Тип Поле, структура вашего действия Redux действительно зависит от вас.
Тем не менее, общий подход – иметь Тип поле и полезная нагрузка поле, как показано ниже:
{
type: " ",
payload: {}
} Тип Поле описывает действие, и все остальные необходимые данные/информация, которая описывает действие, вставляется в полезная нагрузка объект.
Например:
{
type: "withdraw_money",
payload: {
amount: "$4000"
}
}Так что да! Вот что такое действие.
Обработка ответов на действия в редукторе
Теперь, когда вы успешно понимаете, что такое действие, важно увидеть, как они становятся полезными в практическом смысле.
Ранее я сказал, что редуктор принимает Два аргументы. Один Государство другой Действие Отказ
Вот что выглядит простой редуктор:
function reducer(state, action) {
//return new state
} Действие передается в качестве второго параметра к редуктору. Но мы ничего не сделали с этим в самой функции.
Чтобы справиться с действиями, переданными в редуктор, вы обычно напишите Переключатель Заявление в вашем редукторе, как это:
function reducer (state, action) {
switch (action.type) {
case "withdraw_money":
//do something
break;
case "deposit-money":
//do something
break;
default:
return state;
}
}Некоторые люди, кажется, не нравится Переключатель заявление, но это в основном Если/else Для возможных значений на одном поле.
Код выше будет Переключатель над действием Тип и сделать что-то, основываясь на типе действия, передаваемых. Технически, сделать что-нибудь Бит требуется для возврата нового состояния.
Позвольте мне объяснить дальше.
Предположим, что у вас были две гипотетические кнопки, кнопка № 1 и кнопка № 2, на определенной веб-странице, и ваш объект штата выглядел что-то подобное:
{
isOpen: true,
isClicked: false,
}Когда нажата кнопка № 1, вы хотите переключить isopen поле. В контексте приложения React решение простое. Как только кнопка нажала, вы сделаете это:
this.setState({isOpen: !this.state.isOpen})Кроме того, давайте предположим, что когда нажат # 2, вы хотите обновить isclicked поле. Опять же, решение простое, а вдоль линий этого:
this.setState({isClicked: !this.state.isClicked})Хороший.
С приложением redux вы не можете использовать setState () Чтобы обновить объект состояния, управляемого Redux.
Вы должны сначала отправить действие.
Предположим, что действия, как показано ниже:
# 1:
{
type: "is_open"
}# 2:
{
type: "is_clicked"
}В приложении Redux каждое действие протекает через редуктор.
Все они. Итак, в этом примере оба действия № 1 и действия № 2 пройдут через тот же редуктор.
В этом случае как редуктор дифференцирует каждый из них?
Да, вы догадались правильно.
Переключая Action.type Мы можем обрабатывать оба действия без проблем.
Вот что я имею в виду:
function reducer (state, action) {
switch (action.type) {
case "is_open":
return; //return new state
case "is_clicked":
return; //return new state
default:
return state;
}
}Теперь вы видите, почему Переключатель Заявление полезно. Все действия будут течь через редуктор. Таким образом, важно обрабатывать каждый тип действия отдельно.
В следующем разделе мы продолжим с задачей построения мини-приложения ниже:
Изучение действий в приложении
Как я объяснил ранее, всякий раз, когда есть намерение обновить состояние приложения, Действие должен быть отправлен.
Инициируются ли это намерением пользовательского щелчка, или событие Timeout или даже запрос AJAX, правило остается прежним. Вы должны отправить действие.
То же самое касается этого приложения.
Поскольку мы намерены обновить состояние приложения, когда нажатие любых кнопок, мы должны отправить действие.
Во-первых, давайте опишем действия.
Попробуйте посмотрите, если вы получите это.
Вот что я придумал:
Для кнопки React:
{
type: "SET_TECHNOLOGY",
text: "React"
}Для кнопки React-redux:
{
type: "SET_TECHNOLOGY",
text: "React-redux"
}И наконец:
{
type: "SET_TECHNOLOGY",
text: "Elm"
}Легко, верно?
Обратите внимание, что три действия имеют одинаковую Тип поле. Это потому, что три кнопки все делают то же самое. Если бы они были клиентами в банке, то они все будут внесены деньги, но разные суммы денег. Тип действий тогда будет Deposith_money Но с разными сумма поля.
Кроме того, вы заметите, что тип действий все написан заглавными буквами. Это было преднамеренно. Это не обязательно, но это довольно популярный стиль в сообществе Redux.
Надеюсь, вы сейчас понимаете, как я придумал действия.
Представляя акции создателей
Посмотрите на действия, которые мы создали выше. Вы заметите, что мы повторяем несколько вещей.
Для одного, все они имеют одинаковую Тип поле. Если бы нам пришлось отправлять эти действия в нескольких местах, нам придется дублировать их по всему месту. Это не так хорошо. Особенно потому, что это хорошая идея идея, чтобы ваш код был сухим.
Можем ли мы сделать что-то об этом?
Конечно!
Добро пожаловать, Действия Создатели.
Redux имеет все эти модные имена, а? Редукторы, действия, а теперь, акции создатели:)
Позвольте мне объяснить, что это.
Создатели Действия просто функции, которые помогут вам создавать действия. Вот и все. Они являются функциями, которые возвращают объекты действий.
В нашем конкретном примере мы могли бы создать функцию, которая возьмет в себя текст Параметр и вернуть действие, как это:
export function setTechnology (text) {
return {
type: "SET_TECHNOLOGY",
tech: text
}
}Теперь нам не нужно беспокоить дублирование кода везде. Мы можем просто позвонить в Метательства Действие Создатель в любое время, и мы вернемся!
Какое хорошее использование функций.
Используя ES6, созданный выше, который мы создали выше, могут быть упрощены этим:
const setTechnology = text => ({ type: "SET_TECHNOLOGY", text });Теперь это сделано.
Принося все вместе
Я обсудил все важные компоненты, необходимые для создания более продвинутого приложения Hello World в изоляции в более ранних разделах.
Теперь давайте поставим все вместе и построить приложение. В восторге?
Во-первых, давайте поговорим о структуре папки.
Когда вы попадаете в банк, кассир, вероятно, сидит в своей собственной кабине/офисе. Включение также сохраняется в безопасности в безопасной комнате. По веским причинам вещи чувствуют немного более организованные таким образом. Каждый в своем собственном пространстве.
То же самое можно сказать же для redux.
Это обычная практика, чтобы иметь основные актеры приложения redux в своей собственной папке/каталоге.
Актерами, я имею в виду, Редуктор , Действия и магазин Отказ
В вашем каталоге приложений Common Pree Create Create Tree разные папки распространены и назвать каждые после этих актеров.
Это не должно и неизбежно, вы решаете, как вы хотите структурировать ваш проект. Однако для больших приложений это, безусловно, довольно приличная практика.
Теперь мы рефикторуем текущие каталоги приложений, которые у нас есть. Создайте несколько новых каталогов/папок. Один называется Редукторы , другой, магазин и последний, Действия
Теперь у вас должна быть структура компонентов, которая выглядит так:
В каждой из папок создайте index.js файл. Это будет точка входа для каждого из актеров Redux (редукторы, магазин и действия). Я называю их актерами, как актеры фильма. Они являются основными компонентами системы Redux.
Теперь мы реконструируем предыдущее приложение от Глава 2: Ваше первое приложение Redux , использовать эту новую структуру каталогов.
магазин/index.js.
import { createStore } from "redux";
import reducer from "../reducers";
const initialState = { tech: "React " };
export const store = createStore(reducer, initialState);Это так же, как у нас было раньше. Единственное отличие состоит в том, что магазин теперь создан в своем собственном index.js Файл, как имеющий отдельные кабины/офисы для различных актеров Redux.
Теперь, если нам нужен магазин в любом месте в нашем приложении, мы можем безопасно импортировать магазин, как в Импорт магазин из "./store";
С этим говорим, App.js Файл для этого конкретного примера немного отличается от первого.
App.js.
import React, { Component } from "react";
import HelloWorld from "./HelloWorld";
import ButtonGroup from "./ButtonGroup";
import { store } from "./store";
class App extends Component {
render() {
return [
,
];
}
}
export default App;Какая разница?
В строке 4 магазин импортируется из собственной «кабины». Кроме того, сейчас есть Компонент, который принимает в массиве технологий и выпивает кнопки. ButtonGroup Компонент обрабатывает рендеринг трех кнопок под текстом «Hello World».
Кроме того, вы можете заметить, что Приложение Компонент возвращает массив. Это a Реагировать 16 Дуби С реагированием 16, вам не нужно обернуть соседний Jsx Элементы в Div Отказ Вы можете использовать массив, если хотите – но пройти в ключ опоры каждому элементу в массиве.
Это это для App.js компонент.
Реализация ButtonGroup Компонент довольно прост. Вот:
Buttongroup.js.
import React from "react";
const ButtonGroup = ({ technologies }) => (
{technologies.map((tech, i) => (
))}
);
export default ButtonGroup;ButtonGroup это компонент без гражданства, который принимает в массиве технологий, обозначенных Технологии.
Он пестится над этим массивом, используя карта и делает <кнопка> Для каждого из технологий в массиве.
В этом примере на массиве кнопок прошли [«Реагировать», «элма», «Реагирование»]
Сгенерированные кнопки имеют несколько атрибутов. Есть очевидный классное значение для целей стиля. Есть ключ Чтобы предотвратить предупреждение о приеме на Pesly React о рендеринге нескольких элементов без ключа. Гоша, эта ошибка преследует меня каждый раз:(
Наконец, есть Data-Tech атрибут на каждом кнопка слишком. Это называется Атрибут данных Отказ Это способ сохранить дополнительную информацию, которая не имеет визуального представления. Это делает его немного легче снять определенные значения от элемента.
Полностью отображаемая кнопка будет выглядеть так:
Прямо сейчас все делает правильно, но при нажатии на кнопку пока ничего не происходит.
Ну, это потому, что мы еще не предоставили ни одноклассники. Давайте сделаем это сейчас.
В пределах оказывать Функция, давайте настроим OnClick Обработчик:
{technologies.map((tech, i) => ( ))}
Хороший. Давайте напишем Дизатчбция сейчас же.
Не забывайте, что единственная цель этого обработчика состоит в том, чтобы отправить действие, когда произошло щелчок.
Например, если вы нажмете кнопку React, отправьте действие:
{
type: "SET_TECHNOLOGY",
tech: "React"
}Если вы нажмете кнопку red-redux, отправьте это действие:
{
type: "SET_TECHNOLOGY",
tech: "React-redux"
}Итак, вот Дизатчбция функция.
function dispatchBtnAction(e) {
const tech = e.target.dataset.tech;
store.dispatch(setTechnology(tech));
}Хм. Вы вышеупомянуты ли вам смысл?
e.target.dataset.tech Получит атрибут данных, установленный на кнопке, Data-Tech Отказ Следовательно, Tech будет держать значение текста.
store.dispatch () Как вы отправляете действие в Redux, а Селехология () Это создатель действий, который мы написали ранее!
function setTechnology (text) {
return {
type: "SET_TECHNOLOGY",
text: text
}
}Я пошел вперед и добавил несколько комментариев на рисунке ниже, просто так вы понимаете код.
Как вы уже знаете, Store.Dispatch ожидает объекта действия, и ничего другого. Не забывайте Метательства Действие Создатель. Требуется текст кнопки и возвращает необходимое действие.
Кроме того, Tech Кнопки схвачена из набора данных кнопки. Вы видите, именно поэтому у меня было Data-Tech атрибут на каждой кнопке. Таким образом, мы могли бы легко снять технологию от каждой из кнопок.
Теперь мы отправляем правильные действия. Можем ли мы сказать, работает ли это, как ожидалось сейчас?
Действия отправлены. Эта вещь работает?
Во-первых, вот короткий вопрос о викторе. После нажатия на кнопка И, следовательно, отправляя действие, что происходит дальше в Redux? Какой из актеров Redux приходит в игру?
Простой. Когда вы попали в банк с помощью Withraw_money Действие, кому ты идешь? Кассир, да.
То же самое здесь. Действия, когда отправляются, поток через редуктор.
Чтобы доказать это, я буду регистрировать все, что происходит в редуктор.
Редукторы/index.js.
export default (state, action) => {
console.log(action);
return state;
};Затем редуктор возвращает новое состояние приложения. В нашем конкретном случае мы просто возвращаем один и тот же первоначальный Государство Отказ
С console.log () В редукторе давайте посмотрим, что происходит, когда мы нажимаем.
Ах, да!
Действия регистрируются при нажатии кнопок. Что доказывает, что действия действительно проходят через редуктор. Удивительный!
Есть еще одна вещь, хотя. Как только приложение начинается, также происходит странное действие. Похоже, это выглядит:
{type: "@@redux/INITu.r.5.b.c"}Что это?
Ну, не беспокойся себя так много об этом. Это действие, проходящее по себе Redux при настройке вашего приложения. Обычно это называется redux init Действие И он передается в редуктор, когда Redux инициализирует ваше приложение с начальным состоянием приложения.
Теперь мы уверены, что действия действительно проходят через редуктор. Большой!
Хотя это захватывающее, единственная причина, по которой вы идете к кассу с запросом снятия, заключается в том, что вы хотите денег. Если редуктор не принимает действие, мы проходим и делаем что-то с нашим действием, какую ценность это?
Сделать счетчик редуктора
До сих пор редуктор, на котором мы работали, не сделали ничего особенного. Это как кассир, который новый на работу и ничего не делает с нашими Roy_money намерение.
Что именно мы ожидаем, что редуктор будет делать?
На данный момент вот инициация Мы прошли в Createstore Когда Магазин был создан.
const initialState = { tech: "React" };
export const store = createStore(reducer, initialState);Когда пользователь нажимает любую из кнопок, что передает действие на редуктор, новое состояние, которое мы ожидаем, что редуктор возвращается, должен иметь текст действия туда!
Вот что я имею в виду.
Текущее состояние – {Tech: «реагировать»}
Учитывая новое действие типа Set_technology и текст, React-redux :
{
type: "SET_TECHNOLOGY",
text: "React-Redux"
}Что вы ожидаете, что новое состояние будет?
Да, {Tech: "React-redux"}
Единственная причина, по которой мы отправили действие, заключается в том, что мы хотим новое состояние приложений!
Как я уже упоминал ранее, общий способ обрабатывать различные типы действий в редукторе – использовать JavaScript Переключатель Заявление, как показано ниже:
export default (state, action) => {
switch (action.type) {
case "SET_TECHNOLOGY":
//do something.
default:
return state;
}
};Теперь мы Переключатель над Тип действия Отказ Но почему?
Ну, если вы пошли посмотреть кассир, вы могли бы иметь много разных действий.
Вы могли бы захотеть Roy_money или Deposith_money или, может быть, просто Say_Hello Отказ
Кассир умный, поэтому они принимают в свои действия и отвечают на основе вашего намерения.
Это именно то, что мы делаем с редуктором.
Переключатель Оператор проверяет Тип действия.
Что ты хочешь делать? Уйти, депозит, что бы ни …
После этого мы тогда обращаемся к известному случаи мы ожидаем. На данный момент есть только один дело который является Set_technology Отказ
И по умолчанию обязательно верните Государство приложения.
Все идет нормально.
Кассир ( Редуктор ) теперь понимает наши действия. Однако они не дают нам деньги ( государство ) еще.
Давайте сделаем что-то в радиусе дело Отказ
Вот обновленная версия редуктора. Тот, который на самом деле дает нам деньги:)
export default (state, action) => {
switch (action.type) {
case "SET_TECHNOLOGY":
return {
...state,
tech: action.text
};
default:
return state;
}
};Ой, да!
Вы видите, что я там делаю?
Я объясню, что происходит в следующем разделе.
Никогда не мутируйте государство в пределах редукторов
При возврате Государство От редукторов есть что-то, что может сначала отдать вас. Однако, если вы уже пишете хороший React Code, то вы должны быть знакомы с этим.
Вы не должны мутировать Государство получил в вашем редукторе. Вместо этого вы всегда должны вернуть новую копию государства.
Технически, вы никогда не должны делать это:
export default (state, action) => {
switch (action.type) {
case "SET_TECHNOLOGY":
state.tech = action.text;
return state;
default:
return state;
}
};Это именно поэтому редуктор, который я написал, вернул это:
return {
...state,
tech: action.text
};Вместо мутации (или изменений) государство, полученное от редуктора, я возвращаю Новый объект. Этот объект имеет все свойства предыдущего состояния объекта. Благодаря оператору ES6 Spread, ... Государство Отказ Тем не менее, Tech поле обновляется до того, что происходит от действия, действие .text.
Кроме того, каждый редуктор, который вы пишете, должны быть чистыми функциями без побочных эффектов – без вызовов API или обновление значения за пределами объема функции.
Понял?
Надеюсь, да.
Теперь кассир не игнорирует наши действия. Они на самом деле дают нам деньги сейчас!
После этого нажмите кнопки. Это работает сейчас?
Гоша это все еще это не работает. Текст не обновляется.
На этот раз в мире не так?
Подписка для хранения обновлений
Когда вы посещаете банк, пусть кассир знает, что вы задуманные Снятие Действие, и успешно получите свои деньги – так что дальше?
Скорее всего, вы получите оповещение по электронной почте/тексту или некоторое другое мобильное уведомление о том, что вы выполнили транзакцию, а ваша новая баланс счета так и так.
Если вы не получили мобильные уведомления, вы определенно получите какую-то «личную квитанцию», чтобы показать, что на вашей учетной записи была проведена успешная транзакция.
Хорошо, обратите внимание на поток. Действие было возбуждено, вы получили свои деньги, вы получили предупреждение для успешной транзакции.
Кажется, мы испытываем проблему с нашим кодом Redux.
Было успешно инициировано действие, мы получили деньги (штат), но эй, где оповещение для успешного обновления государства?
У нас нет ничего.
Ну, есть решение. Откуда я пришел, вы подписываетесь на получение уведомлений о транзакциях от банка либо по электронной почте/тексту.
То же самое верно для redux. Если вы хотите обновления, вы должны подписаться на них.
Но как?
Store redux, какой магазин вы создаете, имеет Подписаться Метод называется так: Store.subscribe ().
Хорошо называемая функция, если вы спросите меня!
Аргумент прошел в Store.subscribe () это функция, и она будет вызвана всякий раз, когда есть государственное обновление.
За что это стоит, пожалуйста, помните, что аргумент передан в Store.subscribe () должен быть Функция Отказ Хорошо?
Теперь давайте воспользуемся этим.
Подумай об этом. После того, как государство обновляется, что мы хотим или ожидаем? Мы ожидаем, что повторно представляют, верно?
Итак, штат был обновлен. Redux, пожалуйста, перенесите приложение с новыми значениями состояния.
Давайте посмотрим, где приложение оказывается в index.js.
Вот что у нас есть.
ReactDOM.render(, document.getElementById("root")
Это линия, которая оказывает все приложение. Требуется Приложение/> Компонент и делает его в доме. корень ID должен быть конкретным.
Во-первых, давайте абстранируем это в функцию.
Видеть это:
const render = function() {
ReactDOM.render( , document.getElementById("root")
}Так как это сейчас в рамках функции, мы должны вызвать функцию на оказывать приложение.
const render = function() {
ReactDOM.render( , document.getElementById("root")
}
render()Теперь <Приложение/> будет отображаться так же, как раньше.
Используя некоторые вкусности ES6, функция может быть сделана проще.
const render = () => ReactDOM.render(, document.getElementById("root")); render();
Наличие рендеринга <Приложение/> Обернуты в функцию означает, что теперь мы можем подписаться на обновления в магазине, как это:
store.subscribe(render);
Где оказывать вся рендер логика для <Приложение/> – тот, который мы только что повторно изложили.
Вы понимаете, что здесь происходит, верно?
В любое время есть успешное обновление магазина, <Приложение/> Теперь будут повторно представлены новыми значениями состояния.
Для ясности вот <Приложение/> компонент:
class App extends Component {
render() {
return [
,
];
}
}Всякий раз, когда происходит перезарядки, Store.GetState () В строке 4 теперь будет получать обновленное состояние.
Давайте посмотрим, будет ли приложение теперь работает должным образом.
Ага! Это работает, и я знал, что мы могли бы сделать это!
Мы успешно отправляем действие, получаем деньги у кассира, а затем подписываясь на получение уведомлений. Идеальный!
Важное примечание на использовании Store.subscribe ()
Есть несколько предостережений для использования Store.subscribe () Как мы здесь сделали. Это низкоуровневый API Redux.
В производстве, и в основном по причинам эффективности вы, вероятно, будете использовать привязки, такие как React-redux При работе с большими приложениями. На данный момент безопасно продолжать использовать Store.subscribe () для наших учебных целей.
В одном из самых красивых PR Комментарии Я видел за долгое время, Дэн Абрамов , В одном из примеров приложений Redux сказал:
Я верю тому же.
При обучении redux, особенно если вы просто начинаете, вы можете покончить с столько же «Дополнительно».
Учиться ходить Во-первых, тогда вы можете Беги столько, сколько вы хотите.
Хорошо, мы уже сделали?
Да, мы сделаем технически. Тем не менее, есть еще одна вещь, которую я хотел бы показать вам. Я подниму мою браузер devtools и включить мигание на краском.
Теперь, как мы нажимаем и обновляем состояние приложения, обратите внимание на зеленые вспышки, которые появляются на экране. Зеленые вспышки представляют собой части приложения, повторно окрашены или повторно визуализируются двигателем браузера.
Взгляни:
Как вы можете видеть, даже если кажется, что оказывать Функция вызывается каждый раз, когда производится государственное обновление, не все приложение повторно отображается. Просто компонент с новым значением состояния повторно отобразится. В этом случае компонент.
Еще кое-что.
Если текущее состояние приложения оказывает, Hello World React , нажав на Реагировать Кнопка снова не повторно рендерирует, поскольку значение состояния одинаково.
Хороший!
Это React Virtual DOM Различать Алгоритм на работе здесь. Если вы знаете, что некоторые реагируют, вы, должно быть, слышали это раньше.
Так что да. Мы закончили с этим разделом! У меня так весело, объясняя это. Я надеюсь, что вы тоже наслаждаетесь чтением.
Заключение и резюме
Для предположительно простого приложения эта глава была дольше, чем вы, вероятно, ожидали. Но это нормально. Теперь вы оснащены еще большим знанием о том, как работает Redux.
Вот несколько вещей, которые вы узнали в этой главе:
- В отличие от
setState ()В Pure React, единственный способ, которым вы обновляете состояние приложения Redux, направляют действие. - Действие точно описано с простой объектом JavaScript, но он должен иметь
Типполе. - В приложении Redux каждое действие протекает через редуктор. Все они.
- Используя
ПереключательЗаявление, вы можете обрабатывать разные типы действий в вашем редукторе. - Создатели действий являются просто функциями, которые возвращают объекты действий.
- Это обычная практика, чтобы иметь основные актеры приложения redux в своей собственной папке/каталоге.
- Вы не должны мутировать
Государствополучил в вашем редукторе. Вместо этого вы всегда должны вернуть новую копию государства. - Чтобы подписаться на обновления хранения, используйте
Store.subscribe ()метод.
Упражнения
Хорошо, теперь это ваше время, чтобы сделать что-то круто.
- В файлах упражнений я создал простое приложение React Application, которое моделирует банковское приложение пользователя.
Хорошо посмотреть на макет сверху. В дополнение к пользователю способствуют просмотру их общего баланса, они также могут выполнять действия снятия.
Имя и Баланс пользователя хранятся в состоянии приложения.
{
name: "Ohans Emmanuel",
balance: 1559.30
}Есть две вещи, которые вам нужно сделать.
(i) Refactor Состояние приложения будет управляться исключительно Redux.
(ii) обрабатывать действия снятия для фактически истощения баланса пользователя (то есть при нажатии на кнопки, баланс уменьшается).
Вы должны сделать это только через Redux.
В качестве напоминания, при загрузке электронной книги вы обнаружите инструкции о том, как получить сопроводительные файлы кода, файлов упражнений и упражнений.
2. Следующее изображение состоит в том, что прилавка времени, созданного в качестве приложения React.
Государственный объект выглядит так:
{
days: 11,
hours: 31,
minutes: 27,
seconds: 11,
activeSession: "minutes"
}В зависимости от активного сеанса, нажатие на любой из кнопок «Увеличить» или «Уменьшение» следует обновлять значение, отображаемое в счетчике.
Есть две вещи, которые вам нужно сделать.
(i) Refactor Состояние приложения будет управляться исключительно Redux.
(ii) обрабатывать увеличение и уменьшение действий, которые на самом деле влияют на отображаемое время на счетчик.
Глава 4: Строительство Skypey: более продвинутый пример.
Мы прошли долгий путь, и я приветствую вас за следующее.
В этом разделе я пойду через процесс построения более продвинутого примера.
Несмотря на то, что мы охватываем множество оснований на основах Redux, я действительно думаю, что этот пример даст вам более глубокую перспективу относительно того, как некоторые понятия вы узнали, работают на гораздо более широком масштабе.
Мы поговорим о планировании вашего приложения, проектирования и нормализации объекта государства и намного больше. Реальные приложения требуют гораздо больше, чем просто Redux. Вам все равно нужны некоторые CSS и реагируют также.
Пряжка, так как это будет долгая достойная поездка!
Планирование заявки
Хорошо. Вот большой вопрос. Что вы обычно делаете в первую очередь при запуске нового приложения React?
Ну, у всех нас есть наши предпочтения.
Вы разбиваете все приложение на компоненты и построить свой путь?
Сначала вы начинаете с общей макеты приложения?
Как насчет состояния объекта вашего приложения? Вы тоже проводите думая об этом?
На самом деле было много для учета. Я оставлю вас с вашим предпочтительным способом делать вещи.
В здании Skypey Я возьму подход сверху вниз. Мы обсудим общий макет приложения, а затем дизайн объекта состояния приложения, затем мы построим меньшие компоненты.
Опять же, нет идеального способа сделать это. Возможно, для более сложного проекта, возможно, подход нижнего топа подойдет этим.
Еще раз, вот готовый результат, который мы стремимся к:
Разрешение начального макета приложений
Из CLI создайте новое приложение Rection с Create-raction-app, и назовите это Skypey Отказ
create-react-app Skypey
Макет Skypey – это простой 2-контактный макет. Боковая панель фиксированной ширины слева и справа от основного участка, которая занимает оставшуюся ширину просмотра.
Вот быстрое примечание о том, как это приложение оформлено.
Если вы более опытный инженер, обязательно используйте все CSS в решении JavaScript для вас. Для простоты я стимул Skypey приложение с хорошим ol CSS – ничего более.
Давайте взломаемся.
Создайте два новых файла, Sidebar.js и Main.js в корневом каталоге.
Как вы, возможно, догадались, к тому времени, когда мы строим Боковая панель и Главная Компоненты, у нас будет оказано в Приложение Компонент, как это:
App.js.
const App = () => {
return (
);
};Я полагаю, вы знакомы со структурой Create-React-App проект. Есть точка входа в приложение, index.js который делает Приложение компонент.
Прежде чем перейти к созданию боковых панелей и основных компонентов, сначала какое-то домашнее хозяйство CSS. Убедитесь, что узел DOM, где отображается приложение, # Root , занимает всю высоту просмотра вида.
index.csss.
#root {
height: 100vh;
}Пока вы на этом, вы также должны удалить любой нежелательный интервал от Тело :
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}Хороший!
Макет приложения будет структурирован с использованием Flexbox Отказ
Получите сок Flexbox, используя .App А Flex-Container и убедившись, что это занимает 100% доступной высоты.
App.csss.
.App {
height: 100%;
display: flex;
color: rgba(189, 189, 192, 1);
}Теперь мы можем комфортно построить Боковая панель и Главная составные части.
Давайте удержим это проще сейчас.
Sidebar.js.
import React from "react";
import "./Sidebar.css";
const Sidebar = () => {
return ;
};
export default Sidebar;Все, что оказывается, это текст Боковая панель в пределах <Помимо> элемент. Также обратите внимание, что соответствующая таблица стилей, Sidebar.css , был импортирован тоже.
Внутри Sidebar.css Нам нужно ограничить ширину боковой панели, а также несколько других простых стилей.
Sidebar.css.
.Sidebar {
width: 80px;
background-color: rgba(32, 32, 35, 1);
height: 100%;
border-right: 1px solid rgba(189, 189, 192, 0.1);
transition: width 0.3s;
}
/* not small devices */
@media (min-width: 576px) {
.Sidebar {
width: 320px;
}
}Принимая мобильный первый подход, ширина боковой панели будет 80px и 320px на больших устройствах.
Хорошо, сейчас на Главная компонент.
Как и раньше, мы будем держать это просто.
Просто сделайте простой текст в пределах <Главная> элемент.
При разработке приложений вы хотите, обязательно построить постепенно. Другими словами, постройте биты и убедитесь, что приложение работает.
Ниже <Главная> компонент:
import React from "react";
import "./Main.css";
const Main = () => {
return Main Stuff ;
};
export default Main;Опять же, соответствующая таблица стилей, Main.csss , был импортирован.
С визуализированными элементами обоих <Главная/> и <Боковая панель/> , существуют имена классов CSS, .Main и .Sidebar Отказ
Поскольку компоненты оказываются внутри <Приложение/> , .Sidebar и .Main Классы – дети родительского класса, .App Отказ
Помните, что .App это гибкий контейнер. Следовательно, .Main Можно сделать, чтобы заполнить оставшееся пространство в поле зрения:
.Main {
flex: 1 1 0;
}Теперь, вот полный код:
.Main {
flex: 1 1 0;
background-color: rgba(25, 25, 27, 1);
height: 100%;
}Это было просто:)
И вот результат всего кода, который мы записали до этого момента.
Не так увлекательно. Терпение. Мы доберемся туда.
На данный момент базовая планировка приложения установлена. Отличная работа!
Проектирование объекта государства
Способ реагирования Apps создан, состоит в том, что все ваше приложение в основном функция Государство объект.
Независимо от того, создаете ли вы сложное приложение или что-то простое, насколько простым мысльем следует поставить в то, как вы будете структурировать объект состояния вашего приложения.
Особенно при работе с Redux вы можете уменьшить много сложности, разработав правильный объект состояния.
Итак, как ты это делаешь правильно?
Сначала рассмотрите приложение Skypey.
Пользователь приложения имеет несколько контактов.
Каждый контакт в свою очередь имеет ряд сообщений, составляя свой разговор с основным пользователем приложения. Этот вид активирован при нажатии на любой из контактов.
По ассоциации вам не было бы неправой, чтобы иметь такую картину в вашем уме.
Затем вы можете включить, чтобы описать состояние приложения, как это.
Хорошо, в простым JavaScript, вот то, что вы, вероятно, имели:
const state = {
user: [
{
contact1: 'Alex',
messages: [
'msg1',
'msg2',
'msg3'
]
},
{
contact2: 'john',
messages: [
'msg1',
'msg2',
'msg3'
]
}
]В пределах Государство Объект выше – это Пользователь Поле, представленное гигантским массивом. Поскольку у пользователя есть ряд контактов, те, которые представлены объектами в пределах массива. О, поскольку может быть много разных сообщений, они тоже хранятся в массиве.
На первый взгляд это может выглядеть как приличное решение.
Но это?
Если вы должны были получать данные с некоторой спины, структура может выглядеть так же, как это!
Хорошо право?
Нет приятеля. Не так хорошо, как хотелось бы.
Это довольно хорошее представление данных. Похоже, это показывает отношения между каждой сущностью, но с точки зрения состояния вашего фронтального приложения это плохое представление. Плохое слово. Давайте просто скажем, есть лучший способ сделать это.
Вот как я это вижу.
Если вам пришлось управлять футбольной командой, хороший план будет выбрать лучших бомбардировщиков в команде и поместил их на фронт, чтобы заставить вас цели.
Вы можете утверждать, что хорошие игроки могут забить от куда-да. Могу поспорить, что они будут более эффективными, когда они хорошо расположены перед постом ворот оппозиции.
То же самое касается государственного объекта.
Выбирайте передних бегунов в государственном объекте, и поместите их в «Фронт».
Когда я говорю «передние бегуны», я имею в виду поля государственного объекта, на которой вы будете выполнять более кружные действия. Части состояния вы будете создавать, чтение, обновление и удаление чаще всего других. Части состояния, которые являются ядром для приложения.
Это не правило утюга, но это хорошая метрика, чтобы пройти.
Глядя на текущий государственный объект и потребности нашего приложения, мы можем выбрать «передние бегуны» вместе.
Для одного мы будем читать поле «Сообщения» довольно часто – для контакта каждого пользователя. Есть также необходимость редактирования и удаления сообщения пользователя.
Теперь это переднее бегун прямо там.
То же самое касается «контактов» тоже.
Теперь давайте поместим их »впереди.
Вот как.
Вместо того, чтобы иметь вложенные поля «Сообщения» и «Контакты», выберите их и сделайте их первичными ключами в состоянии состояния. Нравится:
const state = {
user: [],
messages: [
'msg1',
'msg2'
],
contacts: ['Contact1', 'Contact2']
}Это все еще неполное представление, но мы значительно улучшили представление государственного объекта приложения.
Теперь давайте продолжим идти.
Помните, что пользователь может сообщить любой из их контактов. Прямо сейчас Сообщения и Контакт Поле в государственном объекте не зависит.
Сделав эти поля первичные ключевые ключи в объекте штата, нет ничего, что показывает отношения между определенным сообщением и связанным контактом. Они независимы, и это не хорошо, потому что нам нужно знать, какой список сообщений принадлежит кому. Не зная, как мы визуализируем правильные сообщения, когда нажат контакт?
Ни за что. Мы не можем.
Вот один способ справиться с этим:
const state = {
user: [],
messages: [
{
messageTo: 'contact1',
text: "Hello"
},
{
messageTo: 'contact2',
text: "Hey!"
}
],
contacts: ['Contact1', 'Contact2']
}Итак, все, что я сделал, сделай Сообщения поле массив объектов сообщения. объекты с Мессагето ключ. Этот ключ показывает, к которому принадлежит контактное сообщение.
Мы приближаемся. Просто немного рефакторинга, и мы закончили.
Вместо того, чтобы просто массив пользователь может быть лучше описан объектом – A Пользователь объект.
user: {
name,
email,
profile_pic,
status:,
user_id
}У пользователя будет имя, электронная почта, изображение профиля, причудливый текстовый статус и уникальный идентификатор пользователя. Идентификатор пользователя важен – и должен быть уникальным для каждого пользователя.
Подумай об этом. Контакты человека также могут быть представлены аналогичным пользователем объектом.
Итак, Контакты Поле в состоянии состояния может быть представлено списком объектов пользователей.
contacts: [
{
name,
email,
profile_pic,
status,
user_id
},
{
name,
email,
profile_pic,
status,
user_id_2
}
]Хорошо. Все идет нормально.
Контакты Поле сейчас представлено огромным массивом Пользователь объекты.
Однако вместо использования массива мы можем иметь Контакты представлен объектом тоже. Вот что я имею в виду.
Вместо того, чтобы оборачивать все контакты пользователя в гигантском массиве, они также могут быть введены в объект.
Увидеть ниже:
contacts: {
user_id: {
name,
email,
profile_pic,
status,
user_id
},
user_id_2: {
name,
email,
profile_pic,
status,
user_id_2
}
}Поскольку объекты должны иметь пару клавишного значения, уникальные идентификаторы контактов используются в качестве клавиш к соответствующим объектам пользователя.
Имеет смысл?
Есть некоторые преимущества для использования Объекты над массивами Отказ Там также нисходящие.
В этом приложении я в основном буду использовать объекты для описания полей в состоянии состояния.
Если вы не привыкли к этому подходу, Это прекрасное видео объясняет некоторые преимущества к этому.
Как будто я сказал ранее, есть несколько недостатков для этого подхода, но я покажу вам, как преодолеть их.
Мы решили, как Контакты поле будет разработано в объекте состояния приложения. Теперь давайте перейдем к Сообщения поле.
В настоящее время у нас есть Сообщения как массив с объектами сообщения.
messages: [
{
messageTo: 'contact1',
text: "Hello"
},
{
messageTo: 'contact2',
text: "Hey!"
}
]Теперь мы определим более подходящую форму для объектов сообщения. Объект сообщения будет представлен объектом сообщений ниже:
{
text,
is_user_msg
}; текст Отображенный текст в чате пузыря. Тем не менее, IS_USER_MSG будет логическим – истинным или ложным. Это важно для дифференцировки, если сообщение из контакта или пользователя приложения по умолчанию.
Глядя на графику выше, вы заметите, что сообщения пользователя и те из контакта создаются по-разному в окне чата. Сообщения пользователя остаются в праве, а контакт, слева. Один синий, другой темный.
Теперь вы понимаете, почему логический, IS_USER_MSG это важно. Нам нужно, чтобы он получил должным образом.
Например, объект сообщения может выглядеть так:
{
text: "Hello there. U good?",
is_user_msg: false
}Теперь, представляя Сообщения Поле в состоянии с объектом, мы должны иметь что-то подобное:
messages: {
user_id: {
text,
is_user_msg
},
user_id_2: {
text,
is_user_msg
}
}Обратите внимание, как я также использую объект вместо массива снова. Кроме того, мы собираемся сопоставить каждое сообщение на уникальный ключ, user_id контакта.
Это потому, что пользователь может иметь разные разговоры с разными контактами, и важно показать это представление в государственном объекте. Например, когда нажатие контакта, нам нужно знать, что нажал!
как нам это сделать? Да, с их user_id Отказ
Представление выше является неполным, но мы сделали много успеха! Сообщения Поле, которое мы представили здесь, предполагают, что каждый контакт (представленный их уникальным идентификазом пользователя) имеет только одно сообщение.
Но это не всегда так. Пользователь может иметь много сообщений, отправленных взад и вперед в разговоре.
Итак, как мы это сделаем?
Самый простой способ состоит в том, чтобы иметь массив сообщений, но вместо этого я представлю это с объектами:
messages: {
user_id: {
0: {
text,
is_user_msg
},
1: {
text,
is_user_msg
}
},
user_id_2: {
0: {
text,
is_user_msg
}
}
}Теперь мы принимаем во внимание, какая сумма сообщений отправляется в разговор. Одно сообщение, два сообщения или более, они теперь представлены в Сообщения представление выше.
Вам может быть интересно, почему я использовал цифры, 0 , 1 И так далее, чтобы создать сопоставление для каждого контактного сообщения.
Я объясню это дальше.
Для того, что стоит, процесс удаления вложенных сущностей из вашего государственного объекта и проектирования его, как мы сделали здесь, называется «Нормализация государственного объекта» Отказ Я не хочу, чтобы ты запутался в том случае, если вы видите, что где-то еще.
Основная проблема с использованием объектов над массивами
Я люблю идею использования объектов над массивами – для большинства случаев использования. Есть некоторые предостережения, которые должны знать, хотя.
Предостережение № 1: Это намного проще повторять массивы в вашей логике
Общая ситуация, которую вы окажетесь, – это необходимость оказать список компонентов.
Например, для рендеринга списка пользователей дано Пользователи PROP, ваша логика будет выглядеть что-то подобное:
const users = this.props.users;
users.map(user => {
return
})Однако, если Пользователи были сохранены в состоянии в качестве объекта, когда он получен и передан как реквизит , Пользователи останется объектом. Вы не можете использовать карта на объектах – и намного сложнее повторять их.
Итак, как мы это решаем?
Решение № 1А:
Использовать Лоташ для итерации над объектами.
Для неиниктированных, Лоташ является надежной учетной библиотекой JavaScript Utility. Даже для итерации над массивами многие будут утверждать, что вы все еще используете Лоташ Как это помогает справиться с значениями FASTYSY.
Синтаксис для использования Лоташ Для итерации над объектами не трудно понять. Похоже, это выглядит:
//import the library
import _ from "lodash"
//use it
_.map(users, (user) => {
return
})Вы называете карта Метод на Лоташ Объект, _.map () Отказ Вы проходите в объекте, который будет итерацией, а затем пройти в функции обратного вызова, как вы, по умолчанию JavaScript карта функция.
Решение № 1В:
Рассмотрим обычный способ, которым вы хотите посмотреть на массив для создания представленного списка пользователей:
const users = this.props.users;
users.map(user => {
return
})Теперь предположим, что Пользователи был объектом. Это означает, что мы не можем карта над ним. Что если бы мы могли легко преобразовать Пользователи на массив без особого хлопота?
Лоташ Снова в спасение.
Вот что бы это было выглядеть так:
const users = this.props.users; //this is an object.
_.values(users).map(user => {
return
})Ты видишь это?
_.values () преобразует объект в массив. Это делает карта возможно!
Вот как это работает.
Если у вас был Пользователи Объект, как это:
{
user_id_1: {user_1_object},
user_id_2 {user_2_object},
user_id_3: {user_3_object},
user_id_4: {user_4_object},
}_.values (пользователи) преобразует это к этому:
[
{user_1_object},
{user_2_object},
{user_3_object},
{user_4_object},
]Да! Массив с значениями объекта. Именно то, что вам нужно повторять. Задача решена.
Есть еще одно предупреждение. Это, возможно, больший.
Предостережение № 2: Сохранение порядка
Возможно, это причина, по которой люди используют массивы. Массивы сохраняют порядок их ценностей.
Вы должны увидеть пример, чтобы понять это.
const numbers = [0,3,1,6,89,5,7,9]
Что бы вы ни делали, выбирая ценность Числа Всегда вернет один и тот же массив, при этом порядок входов неизменных.
Как насчет объекта?
const numbers = {
0: "Zero",
3: "Three",
1: "One",
6: "Six",
89: "Eighty-nine",
5: "Five",
7: "Seven",
9: "Nine"
}Порядок чисел такой же, как и в массиве раньше.
Теперь смотрите мне скопируйте и вставьте это в консоль браузера, а затем попробуйте получить значения.
Хорошо, вы могли бы пропустить это. Смотри ниже:
Смотрите основные моменты на изображении выше. Заказ значений объекта не возвращается таким же образом!
Теперь, в зависимости от такого приложения, которое вы строите, это может вызвать очень серьезные проблемы. Особенно в приложениях, где заказ имеет первостепенное значение.
Вы знаете какие-либо примеры такого приложения?
Ну, я делаю. Приложение чата!
Если вы представляете разговоры пользователя в качестве объекта, вы уверены, что порядок отображаются сообщения!
Вы не хотите, чтобы сообщение отправлено вчера, показывая так, как было отправлено сегодня. Заказать вопросы.
Итак, как бы вы решили это?
Решение № 2:
Держите отдельный массив идентификаторов для обозначения заказа.
Вы, должно быть, видели это раньше, но вы, возможно, не обращали внимания.
Например, если у вас был следующий объект:
const numbers = {
0: "Zero",
3: "Three",
1: "One",
6: "Six",
89: "Eighty-nine",
5: "Five",
7: "Seven",
9: "Nine"
}Вы можете сохранить другой массив для обозначения порядка значений.
numbersOrderIDs: [0, 3, 1, 6, 89, 5, 7, 9]
Таким образом, вы всегда можете отслеживать порядок ценностей – независимо от поведения объекта. Если вам нужно добавлять значения на объект, вы делаете это, но нажмите связанный идентификатор в UsersorderIds также.
Важно знать об этих вещах, поскольку вы не всегда можете иметь контроль над некоторыми вещами. Вы можете забрать приложения с помощью штата, смоделированного таким образом. И даже если вам не нравится идея, вы определенно должны быть в знании.
Ради простоты идентификаторы сообщений для приложения Skypey всегда будут в порядке – поскольку они пронумеруются в увеличении значений с нуля вверх.
Это может быть не так в реальном приложении. У вас могут быть странные автоматические идентификаторы, которые выглядят как гибберцы, такие как Y68FND0A9WYB Отказ
В таких случаях вы хотите сохранить отдельный массив для отслеживания порядка значений.
Вот и все!
Стоит отметить, что весь процесс Нормалицин G Государственный объект может быть обобщен следующим образом:
• Каждый тип данных должен иметь свой ключ в состоянии состояния.
• Каждый ключ должен хранить отдельные элементы в объекте, с идентификаторами элементов в качестве клавиш и самими элементами как значения.
• Любые ссылки на отдельные элементы должны выполняться, сохраняя идентификатор элемента.
• В идеале сохраняйте массив идентификаторов, чтобы указать упорядочение.
Рекомендация по дизайну объекта состояния
Теперь я знаю, что это был длинный дискурс на структуре государственного объекта.
Сейчас не может показаться важно, но, поскольку вы создаете проекты, вы приедете, насколько бесценным положил некоторую мысль в проектирование вашего состояния. Это поможет вам выполнить трудные операции намного легче, уменьшит множество чрезмерно сложной логики в ваших редукторах, а также поможет вам воспользоваться композицией редуктора, термин, который я буду описать позже в этой книге.
Я хотел, чтобы вы понять причину моих решений, и сможете принимать обоснованные решения, поскольку вы создаете свои собственные приложения. Я верю, что вы теперь уполномочены правильной информацией.
Со всем сказанным и сделанным, вот визуальное представление объекта состояния Skypey:
Изображение предполагает только два контактах пользователя. Пожалуйста, хорошо посмотрите на это.
Создание списка пользователей
Двигаясь, пришло время написать какой-то код. Во-первых, вот цель этого раздела. Чтобы создать список пользователей, показанных ниже:
Что нужно для построения этого?
С высокого уровня должно быть довольно ясно, что внутри Боковая панель Компонент, есть необходимость рендеринга списка контактов пользователя.
Предположительно, внутри Боковая панель У вас может быть что-то подобное:
contacts.map(contact =>)
Понял?
Вы напечатаете через некоторые Контакты данные из штата, а для каждого Контакт Вы визуете Пользователь компонент.
Но откуда приходят данные для этого?
В идеале, и в реальном мире сценарий вы получите эти данные с сервера с помощью вызова AJAX. Для наших учебных целей это приносит в слой сложности, мы можем избежать – пока нет.
Итак, в отличие от приема данных удаленно с сервера, я создал несколько Функции Это будет справиться с созданием данных для приложения. Мы будем использовать эти статические данные для создания приложения.
Например, есть Контакты Переменная уже создана внутри Static-data.js , это всегда будет возвращать случайно сгенерированный список контактов. Все, что вам нужно сделать, это импортировать это в приложение. Нет вызовов Ajax.
Таким образом, создайте новый файл в корневом каталоге проекта и вызовите его Static-data.js.
Скопируйте содержимое Гист здесь в этот файл. Мы будем использовать это довольно скоро.
Настройка магазина
Давайте быстро перейдем к процессу настройки хранилища приложения, чтобы мы могли получить данные, необходимые для создания списка пользователей в боковой панели.
Один из первых шагов при создании приложения redux устанавливает магазин redux. Поскольку именно поэтому данные будут прочитаны из того, что он становится обязательным разрешением этого.
Итак, пожалуйста, установите redux от CLI с:
yarn add redux
Как только установка будет сделана, создайте новую папку, называемую магазин И в каталоге создайте новый index.js файл.
Не забывайте аналогию, имеющих основные актеры Redux в своих собственных каталогах.
Как вы уже знаете, магазин будет создан через Createstore Функция завода из redux нравится:
магазин/index.js.
import { createStore } from "redux";
const store = createStore(someReducer, initialState);
export default store;Redux Createstore Необходимо знать о редукторе (запоминание в магазине и отношениях, которые я объяснил ранее).
Теперь отредактируйте вторую строку, чтобы выглядеть так:
const store = createStore(reducer, {contacts});Теперь импортируйте Редуктор и Контакты из статических данных:
import reducer from "../reducers";
import { contacts } from "../static-data";Так как мы на самом деле не создали ни одного Редукторы Справочник, пожалуйста, сделайте это сейчас. Также создайте index.js Файл с этим Редукторы каталог.
Теперь создайте редуктор.
Редукторы/index.js.
export default (state, action) => {
return state;
};Редуктор – это просто функция, которая принимает в Государство и Действие и возвращает новый Государство Отказ
Если я потерял тебя в создании магазина, const (редуктор, {контакты}); Вы должны помнить, что второй аргумент в Createstore это начальное состояние приложения.
Я установил это на объект {контакты} Отказ
Это синтаксис ES6, похожий на это: {Контакты: Контакты} с Контакты ключ и значение Контакты от Static-data Отказ
Там нет способа знать, что мы сделали, правильно. Давайте попытаемся это исправить.
В Index.js Вот что вы должны иметь сейчас:
Index.js.
import React from "react"; import ReactDOM from "react-dom"; import "./index.css"; import App from "./App"; import registerServiceWorker from "./registerServiceWorker"; ReactDOM.render(, document.getElementById("root")); registerServiceWorker();
Как мы сделали с первым примером, рефактором Reactom.runder Позвоните, чтобы сидеть внутри оказывать функция.
const render = () => {
return ReactDOM.render( , document.getElementById("root"));
};Затем включите функцию Render, чтобы приложение правильно регларировать.
render()
Теперь импортируйте магазин Вы создали ранее …
import store from "./store";
И убедитесь, что в любое время магазин обновляется, оказывать Функция вызывается.
store.subscribe(render);
Хороший!
Теперь давайте воспользуемся этой установкой.
Каждый раз в магазине обновляются и вызывают оказывать Давайте войдем в систему Государство от магазина.
Вот как:
const render = () => {
fancyLog();
return ReactDOM.render( , document.getElementById("root"));
};Просто назовите новую функцию, fancylog () , что вы скоро напишите.
Вот …| Фанчилог Функция:
function fancyLog() {
console.log("%c Rendered with ? ??", "background: purple; color: #FFF");
console.log(store.getState());
}Хм. Что я сделал?
Console.log (Store.getState ()) Это немного знакомо. Это будет регистрировать состояние, полученное из магазина.
Первая строка, console.log («% C визуализации с?», «Фон: фиолетовый; цвет: #fff»); Буду регистрировать текст, «визуализируется с …», плюс какой-то emoji и какой-то стиль CSS, чтобы сделать его различимым. % c Написано перед текстом «оказанных …», позволяет использовать стайлинг CSS.
Хватит болтать. Вот полный код:
index.js.
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
import store from "./store";
const render = () => {
fancyLog();
return ReactDOM.render( , document.getElementById("root"));
};
render();
store.subscribe(render);
registerServiceWorker();
function fancyLog() {
console.log("%c Rendered with ? ??", "background: purple; color: #fff");
console.log(store.getState());
}Вот вот зарегистрирован государственный объект.
Как вы можете видеть, в государственном объекте является Контакты поле, которое содержит контакты, доступные для конкретного пользователя. Структура данных так, как мы обсуждали до сих пор. Каждый контакт сопоставлен со своими Логин пользователя
Мы сделали достойный прогресс.
Передача данных боковой панели через реквизиты
Если вы сейчас посмотрите на весь код, вы согласитесь, что точка входа в приложение остается index.js Отказ
Index.js затем оказывает Приложение компонент. Приложение компонент затем несет ответственность за рендеринг Главная и Боковая панель составные части.
Для Боковая панель Чтобы получить доступ к необходимым данным контактов, мы передадимся в данные через реквизиты.
В App.js Восстановить Контакты из магазина и передайте его на Боковая панель нравится:
App.js.
const App = () => {
const { contacts } = store.getState();
return (
);
};Как я уже сделал на скриншоте выше, осмотрите компонент боковой панели, и вы найдете Контакты прошел как опоры. Контакты – это объект с сопоставленными идентификаторами на объекты пользователя.
Теперь мы можем приступить к рендерингу контактов.
Сначала установите Лоташ от CLI :
yarn add lodash
Импорт Лоташ в App.js.
import _ from lodash
Я знаю. Подчеркивание выглядит смешно, но это хорошая конвенция. Вы будете любить это:)
Теперь, чтобы использовать любой из методов утилиты Лоташ Любится к нам, позвоните в методы на импортном подчерке, например .fakemethod () Отказ
Теперь поставь Лоташ для хорошего использования. Используя один из Лоташ Уметели функции, Контакты Объект может быть легко преобразован в массив при прохождении в виде опоры.
Вот как:
Вы можете прочитать больше о Лоташ .values Метод Если хочешь. В двух словах он создает массив из всех ключевых значений, прошедших в.
Теперь давайте действительно сделаем что-то в боковой панели.
Sidebar.js.
import React from "react";
import User from "./User";
import "./Sidebar.css";
const Sidebar = ({ contacts }) => {
return (
);
};
export default Sidebar;В разделе «Кодовой блок выше» мы напечатаем над контактами PROP и Render A Пользователь Компонент для каждого Контакт Отказ
Чтобы предотвратить клавишу предупреждения «Реагирование», «Контакт» user_id используется в качестве ключа. Кроме того, каждый контакт передан как Пользователь опора Пользователь компонент.
Создание пользовательского компонента
Мы оказываем Пользователь Компонент внутри Боковая панель , но этот компонент пока не существует.
Пожалуйста, создайте User.js и User.csss файл в корневом каталоге.
Сделал это?
Теперь, вот содержание User.js файл:
User.js.
import React from "react";
import "./User.css";
const User = ({ user }) => {
const { name, profile_pic, status } = user;
return (
{name}
{status}
);
};
export default User;Не позволяйте большому количеству кода обмануть вас. Это на самом деле очень легко читать и понимать. Иметь второй взгляд.
Имя , profile_pic URL и Статус Пользователя получены из реквизита через разрушительную: const {name, profty_pic, статус;
Эти значения затем используются в операторе возврата для правильного рендеринга, и вот результат этого:
Приведенный выше приведенный выше супер уродливый, но это указание, что это работает!
Теперь давайте стилься этим.
Во-первых, предотвратить перечень пользователей из переполнения контейнера боковой панели.
Sidebar.css.
.Sidebar {
...
overflow-y: scroll;
}Кроме того, шрифт уродливый. Давайте изменим это.
Index.csss.
@import url("https://fonts.googleapis.com/css?family=Nunito+Sans:400,700");
body {
...
font-weight: 400;
font-family: "Nunito Sans", sans-serif;
}Наконец, обрабатывать общий дисплей Пользователь компонент.
User.csss.
.User {
display: flex;
align-items: flex-start;
padding: 1rem;
}
.User:hover {
background: rgba(0, 0, 0, 0.2);
cursor: pointer;
}
.User__pic {
width: 50px;
border-radius: 50%;
}
.User__details {
display: none;
}
/* not small devices */
@media (min-width: 576px) {
.User__details {
display: block;
padding: 0 0 0 1rem;
}
.User__details-name {
margin: 0;
color: rgba(255, 255, 255, 0.8);
font-size: 1rem;
}
}Поскольку это не книга CSS, я пропускаю некоторые объяснения стиля. Однако, если что-нибудь смущает вас, просто спросите меня в твиттере И я буду рад помочь.
Вуаля!
Вот красивый дисплей, который мы получили сейчас:
Удивительный!
Мы ушли из ничего, чтобы иметь красивый список пользователей, представленных на экране.
Если вы используете, измените размер браузера, чтобы увидеть красивый вид на мобильном телефоне.
Повесить там!
Есть вопросы?
Это прекрасно нормально, чтобы иметь вопросы.
Самый быстрый способ связаться со мной будет твитнуть ваш вопрос через твиттер , с хэштегом, #OnderstandingRedux Отказ Таким образом, я могу легко найти и ответить на ваш вопрос.
Вам не нужно пропускать реквизиты
Посмотрите на высокую структуру высокого уровня ui Skypey ниже:
В традиционных приложениях RACTS (без использования контекста API) вы должны передать реквизиты от <Приложение/> к <Боковая панель/> и <Главная/>
С redux, однако, вы не связано этим правилом.
Если определенный компонент нуждается в доступе к значению из объекта состояния, вы можете просто добраться до магазина и получить текущее состояние.
Например, <Боковая панель/> и <Главная/> может получить доступ к магазину Redux без необходимости зависеть от <Приложение/>
Единственная причина, по которой я не сделал так вот потому, что <Приложение/> Прямой родитель, с <Боковая панель/> и <Главная/> Не более одного уровня глубоко в иерархии компонентов.
Как вы увидите в более поздних разделах, для компонентов, которые вложены глубже в иерархии компонентов, мы напрямую доберемся до магазина Redux для получения текущего состояния.
Там нет необходимости пропускать реквизиты.
Вы будете любить графику ниже. Это идет еще дальше, чтобы описать необходимость не пропускать реквизиты при работе с redux.
Контейнерные и компонент Папка Структура
Есть немного рефакторинга, который вам нужно сделать, прежде чем перейти к кодированию приложения Skypey.
В приложениях Redux это общий шаблон, чтобы разделить свои компоненты на два разных каталога.
Каждый компонент, который переговаривает непосредственно для redux, то есть ли это для извлечения состояния из магазина или отправлять действие, должно быть перемещено в Контейнеры каталог.
Другие компоненты, те, которые делают не Поговорите с redux, должны быть перенесены на Компоненты каталог.
Так так так. Зачем пройти через хлопот?
Для одного ваша кодовая база становится немного очистителем. Также становится легче найти определенные компоненты, если вы знаете, говорят ли они с redux или нет.
Итак, продолжайте.
Посмотрите на компоненты в текущем состоянии приложения и соответствующим образом перемотали.
Так что вы не закрутите вещи, не забудьте перемещать ассоциированные компоненты CSS файл.
Вот мое решение:
- Создайте две папки:
КонтейнерыиКомпонентыОтказ App.jsпопытки получитьКонтактыот магазина. Итак, двигайсяApp.jsиApp.csssкКонтейнерыпапка.- Переместить
Sidebar.js,Sidebar.css,Main.jsиMain.csssкКомпонентыпапка. Они не разговаривают с Redux напрямую для чего угодно. - Пожалуйста, не двигайтесь
Index.jsиIndex.csssОтказ Это точка входа в приложение. Просто оставьте те, кто в корне справочника проекта. - Пожалуйста, переместите
User.jsиUser.csssкКонтейнерыкаталог.ПользовательКомпонент не разговаривает с redux еще Но это будет Отказ Помните, что когда приложение завершено, на нажав Пользователь из боковой панели, их сообщения будут показаны. По словам, действие будет отправлено. В грядущих разделах мы построим это. - К настоящему времени многие ваши импортные URL-адресов будут нарушены, то есть компоненты, которые импортировали эти перемещенные компоненты. Вы должны изменить свой импорт URL. Я оставлю это до тебя. Это простое исправление:)
Вот пример решения для # 6 выше: в App.js изменить Боковая панель и Главная Импорт к этому:
import Sidebar from "../components/Sidebar"; import Main from "../components/Main";
В отличие от первого:
import Sidebar from "./Sidebar"; import Main from "./Main";
Понял?
Вот несколько советов, чтобы решить проблему самостоятельно:
- Проверьте
Sidebar.jsИмпорт оператора дляПользователькомпонент. - Проверьте
Index.jsИмпорт оператора дляПриложениекомпонент. - Проверьте
App.jsИмпорт оператора дляхранить
Когда это сделано, у вас будет работать Skypey, как ожидалось!
Рефакторинг для установки исходного состояния от редуктора
Во-первых, пожалуйста, посмотрите на создание магазин в магазин/index.js Отказ В частности, рассмотрим эту линию кода:
const store = createStore(reducer, { contacts });Начальный объект состояния передается непосредственно в Createstore Отказ Помните, что магазин создан с подписью, Createstore (редуктор, инициал) Отказ В этом случае начальное состояние было установлено на объект, {Контакты: Контакты}
Несмотря на то, что этот подход работает, это обычно используется для Серверная сторона рендеринг (не беспокойтесь, если вы не знаете, что это значит). На данный момент понимайте, что этот подход установки начального состояния в Createstore больше используется в реальном мире для рендеринга боковых серверов.
Прямо сейчас удалите начальное состояние в Createstore метод.
У нас будет начальное состояние приложения, установленного исключительно редуктором.
Поверьте мне, вы получите такое повешение.
Вот что магазин/index.js Файл будет выглядеть как только вы удалите начальное состояние из Createstore Отказ
import { createStore } from "redux";
import reducer from "../reducers";
const store = createStore(reducer);
export default store;И вот текущее содержание Редуктор/index.js файл:
export default (state, action) => {
return state;
};Пожалуйста, измените это к этому:
import { contacts } from "../static-data";
export default (state = { contacts }, action) => {
return state;
};Итак, что здесь происходит?
Используя параметры ES6 по умолчанию, мы установили параметр состояния в исходное значение {контакты} Отказ
Это по сути так же, как {Контакты: Контакты} Отказ
Следовательно, Возврат государства Заявление внутри редуктора вернет это значение, {Контакты: Контакты} как начальное состояние приложения.
На данный момент приложение сейчас работает – просто как раньше. Единственная разница вот в том, что начальное состояние приложения теперь управляется редуктором.
Давайте продолжим рефакторинг.
Состав редуктора
Во всех приложениях мы создаем до сих пор, мы использовали только один редуктор для управления всей состоянием приложений.
Что такое подразумевание этого?
Это как только один кассир во всем банковском зале. Насколько масштабируется это?
Даже если кассир может эффективно выполнять всю работу, это может быть более управляемым – и, возможно, лучший клиентский опыт – иметь более одного кассира в банковском зале.
Кто-то должен присутствовать на всех, и это много работы только для одного человека!
То же самое касается ваших приложений Redux.
В вашем приложении обычно есть несколько редукторов, в отличие от одной редуктора, обрабатывающей все операции государства. Эти редукторы затем объединяются в одну.
Например, в банковском зале может быть 5 или 10 кассиров, но все они объединили все служить одной цели. Вот как это тоже работает.
Рассмотрим государственный объект приложения Hello World, который мы построили ранее.
{
tech: "React"
}Довольно просто.
Все, что у нас было, было иметь один Редуктор управляет всеми обновлениями состояния.
Однако рассмотрим государственный объект более сложной приложения Skypey:
Наличие единого редуктора управляет всем объектом состояния, является выполненным – но не лучший подход.
Вместо того, чтобы весь объект, управляемый одним редуктором, что, если у нас был один редуктор, управляйте одним полем в государственном объекте?
Как одно на одно сопоставление?
Вы видите, что мы там делаем? Представляя больше кассиров!
Состав редуктора требует, чтобы один редуктор обрабатывает состояние обновления состояния для одного поля в объекте состояния.
Например, для Сообщения поле, у вас есть Сообщения Отказ Для Контакты поле, у вас тоже есть ContactMeducer и так далее.
Одним из важно отметить, что возвращаемое значение из каждого из редукторов является исключительно для поля, которую они представляют.
Итак, если бы у меня был Сообщения написано так:
export const function messagesReducer (state={}, action) {
return state
} Государство Вернулся здесь не является состоянием всего приложения.
Нет.
Это только ценность Сообщения поле.
То же самое касается других редукторов.
Понял?
Давайте посмотрим на это на практике, и то, как именно эти редукторы объединяются для одной цели.
Рефакторинг Skypey использовать несколько редукторов
Помните, как я говорил о нескольких редукторах, обрабатывающих каждое поле в государственном объекте?
Прямо сейчас вы можете сказать, что мы сделаем следующий несколько редукторов, как видно на рисунке ниже:
Теперь для каждого поля в объекте штата мы создадим соответствующий редуктор. Текущие на этом этапе есть, Контакты и Пользователь Отказ
Давайте перейдем на то, как это затрагивает наш код сначала. Тогда я сделаю шаг назад, чтобы объяснить, как он снова работает.
Посмотрите на Редуктор/index.js :
import { contacts } from "../static-data";
export default (state = contacts, action) => {
return state;
};Переименуйте этот файл в Contacts.js Отказ
Это станет редуктором контактов.
Создать user.js Файл в пределах Редукторы каталог.
Это будет редуктор пользователя.
Вот контент:
import { generateUser } from "../static-data";
export default function user(state = generateUser(), action) {
return state;
}Опять же, я создал GenerateUser Функция для создания некоторой статической информации пользователя.
Использование параметров ES6 по умолчанию, начальное состояние установлено к результату взыскания этой функции. Поэтому Возврат государства Теперь вернет объект пользователя.
Прямо сейчас у нас есть два разных редуктора. Давайте комбинируем их для большего доброго:)
- Создать
index.jsФайл в каталоге редукторов
Во-первых, импортировать два редуктора, Пользователь и Контакты :
import user from "./user"; import contacts from "./contacts";
Чтобы объединить эти редукторы, нам нужен функция помощника Коммунатории от redux.
Импортировать это так:
import { combineReducers } from "redux";Теперь index.js будет экспортировать комбинацию обоих редукторов, как это:
export default combineReducers({
user,
contacts,
});Обратите внимание, что Коммунатории Функция принимает в объекте. Объект, форма которого точно так же, как объект состояния приложения.
Блок кода такой же, как это:
export default combineReducers({
user: user,
contacts: contacts
})Объект имеет ключи Пользователь и Контакты , как и государственный объект, который мы имели в виду.
А как насчет ценностей этих клавиш?
Значения приходят от редукторов!
Важно понять это. Хорошо?
Я заблудился. Как эта работа снова?
Позвольте мне сделать шаг назад и объяснить, как состав редуктора снова работает. На этот раз с другой точки зрения.
Рассмотрим объект JavaScript ниже:
const state = {
user: "me",
messages: "hello",
contacts: ["no one", "khalid"],
activeUserId: 1234
}Теперь предположим, что вместо того, чтобы значения клавиш жесткими, мы хотели, чтобы он был представлен функциями. Это может выглядеть так:
const state = {
user: getUser(),
messages: getMsg(),
contacts: getContacts(),
activeUserId: getID()
}Это предполагает, что GetUser () также вернется предыдущее значение, «Я» Отказ То же самое касается других замененных функций.
Все еще следуем?
Теперь давайте переименуем эти функции.
const state = {
user: user(),
messages: messages(),
contacts: contacts(),
activeUserId: activeUserId()
}Теперь функции имеют имена, идентичные их соответствующим клавишам объекта. Вместо GetUser () У нас сейчас есть Пользователь () Отказ
Давайте воображаемся.
Представьте, что существует определенная функция утилиты, импортированной из какой-либо библиотеки. Давайте назовем эту функцию, Killerfunction Отказ
Теперь Killerfunction позволяет сделать это:
const state = killerFunction({
user: user,
messages: messages,
contacts: contacts,
activeUserId: activeUserId
})Что изменилось?
Вместо того, чтобы вызвать каждую из функций, вы просто пишете имена функций. Killerfunction позаботится о том, чтобы вызвать функции.
Теперь, используя ES6, мы можем упростить код в дальнейшем:
const state = killerFunction({
user,
messages,
contacts,
activeUserId
})Это то же самое, что и предыдущий код кода. Предполагая, что функции находятся в области охвата и имеют одинаковое имя (идентификатор) в качестве клавиши объекта.
Понял?
Теперь это своего рода, как Комбинергер от Redux работает.
Значения каждого ключа в вашем объекте вашего государства будут получены из Редуктор Отказ Не забывайте, что редуктор – это просто функция.
Так же, как Killerfunction , Коммунатории способен убедиться, что значения получены от вызова пропущенных функций.
Все ключ и значения, созданные вместе, будут затем привести к объекту состояния приложения.
Вот и все!
Важный момент, чтобы всегда помнить, что при использовании Коммунатории , значение, возвращенное из каждого редуктора, не является состоянием приложения.
Это только ценность Из определенного ключа они представляют в государственном объекте!
Например, Пользователь Редуктор возвращает значение для Пользователь ключ в состоянии. Аналогично, Сообщения Редуктор возвращает значение для Сообщения ключ в состоянии.
Теперь вот полное содержание Редукторы/index.js :
import { combineReducers } from "redux";
import user from "./user";
import contacts from "./contacts";
export default combineReducers({
user,
contacts
});Теперь, если вы проверяете журналы, вы найдете Пользователь и Контакты прямо там в государственном объекте.
Создание пустого экрана
Прямо сейчас Главная Компонент просто отображает текст, Основные вещи Отказ Это не то, что мы хотим.
Конечная цель – показать пустой экран, но показать пользовательские сообщения при нажатии контакта.
Давайте построим пустой экран.
Для этого нам понадобится новый компонент, называемый, Just.js Отказ Пока вы на этом, также создайте соответствующий файл CSS, Story.csss Отказ
Пожалуйста, создайте их в Компоненты каталог.
<Пустой/> сделает разметку для пустого экрана. Для этого это потребует определенного Пользователь пропры
Определенно, Пользователь должен быть передан из состояния заявления. Не забывайте общую структуру государственного объекта, которую мы решили ранее:
Итак, вот текущее содержание <Главная/> компонент:
import React from "react";
import "./Main.css";
const Main = () => {
return Main Stuff ;
};
export default Main;Это просто возвращает текст, Основные вещи Отказ
<Главная/> Компонент несет ответственность за отображение <Пустой/> Компонент, когда пользователь не активен. Как только пользователь нажат, <Главная/> Оказывает разговоры пользователя клика. Это может быть представлено компонентом, Отказ
Для этого рендеринг переключается на работу и для <Главная/> рендерировать либо <Пустой/> или нам нужно отслеживать определенные ActiveUserid Отказ
Например, по умолчанию ActiveUserid будет нулевой, то <Пустой/> будет показано.
Однако, как только пользователь нажат, ActiveUserid становится user_id контакта щелчка. Теперь <Главная/> сделает компонент.
Круто, да?
Для этого на работу мы будем держать новую поле в государственном объекте, ActiveUserid
К настоящему времени вы уже должны знать дрель. Чтобы добавить новое поле в объект штата, мы будем настроить это в редукторах.
Создать новый файл, ActiveUserid.js В Редукторы папка.
И вот содержание файла:
Редукторы/ActiveUserid.js.
export default function activeUserId(state = null, action) {
return state;
}По умолчанию он возвращает null Отказ
Теперь подключите этот недавно созданный редуктор к Комбинергер Способ звонить так:
...
import activeUserId from "./activeUserId";
export default combineReducers({
user,
contacts,
activeUserId
});Теперь, если вы проверяете журналы, вы найдете ActiveUserid прямо там в государственном объекте.
Давайте двигаться дальше.
В App.js Получите Пользователь и ActiveUserid Из магазина, как это:
const { contacts, user, activeUserId } = store.getState();То, что мы ранее имели это:
const { contacts } = store.getState();Теперь пропустите эти значения как реквизит к <Главная/> компонент.
То, что мы ранее имели это:
Теперь давайте сделали логику рендеринга в <Главная/>
перед:
import React from "react";
import "./Main.css";
const Main = () => {
return Main Stuff ;
};
export default Main;сейчас же:
import React from "react";
import "./Main.css";
import Empty from "../components/Empty";
import ChatWindow from "../components/ChatWindow";
const Main = ({ user, activeUserId }) => {
const renderMainContent = () => {
if (!activeUserId) {
return ;
} else {
return ;
}
};
return {renderMainContent()} ;
};
export default Main;То, что изменилось, не сложно понять. Пользователь и ActiveUserid получены как реквизиты. Оператор возврата в компоненте имеет функцию randermaincontent вызывается.
Все randermaincontent Есть ли проверка, если ActiveUserid не существует Если это не так, он отображает пустой экран. Если это существует, то ChatWindow оказывается.
Большой!
У нас нет Пустой и ChatWindow Компоненты построены еще.
Прости меня, я собираюсь вставить много кода одновременно.
Изменить Just.js Файл, чтобы содержать это:
import React from "react";
import "./Empty.css";
const Empty = ({ user }) => {
const { name, profile_pic, status } = user;
const first_name = name.split(" ")[0];
return (
Welcome, {first_name}
Status: {status}
Search for someone to start chatting with or go to Contacts to see who
is available
);
};
export default Empty;Ой Что такое все этот код ???
Сделайте шаг назад, это не так сложно, как кажется.
<Пустой/> Компонент берет в Пользователь пропры Этот опрос пользователя является объектом, имеющим следующую форму:
{
name,
email,
profile_pic,
status,
user_id:
}Использование синтаксиса Разрушивания ES6, захватите Имя , profile_pic и Статус От объекта пользователя:
const { name, profile_pic, status } = user;Для большинства пользователей Имя содержит два слова, такие как Оганес Эммануил Отказ Возьмите первое слово и назначите его переменной first_name нравится:
const first_name = name.split(" ")[0];Заявление об возврате просто выплевывает кусок разметки.
Вы увидите результат этого очень скоро.
Прежде чем мы продолжим, давайте не будем забывать создать ChatWindow Компонент внутри Контейнеры каталог.
ChatWindow Будет нести ответственность за отображение разговоров для активного контакта пользователя, и он собирается сделать много прямого разговора с Redux!
В Chatwindow.js Напишите следующее:
import React from "react";
const ChatWindow = ({ activeUserId }) => {
return (
Conversation for user id: {activeUserId}
);
};
export default ChatWindow;Мы вернемся к тому, чтобы плоть это. Прямо сейчас это достаточно хорошо.
Сохраните все изменения, которые мы сделали до сих пор, и вот что у меня есть!
У вас тоже должно быть что-то очень похожее.
Пустой экран работает, но это уродливо, и никто не любит уродливые приложения.
Я написал CSS для <Пустой/> компонент.
Just.csss.
.Empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
.Empty__name {
color: #fff;
}
.Empty__status,
.Empty__info {
padding: 1rem;
}
.Empty__status {
color: rgba(255, 255, 255, 0.9);
border-bottom: 1px solid rgba(255, 255, 255, 0.7);
}
.Empty__img {
border-radius: 50%;
margin: 2rem 0;
}
.Empty__btn {
padding: 1rem;
margin: 1rem 0;
font-weight: bold;
font-size: 1.2rem;
border-radius: 30px;
outline: 0;
}
.Empty__btn:hover {
background: rgba(255, 255, 255, 0.7);
cursor: pointer;
}Просто хорошие OL ‘CSS. Могу поспорить, вы можете понять стили.
Теперь вот результат этого:
Вот результат с докваркой Devtools:
Теперь, что определенно выглядит хорошо!
Создание окна чата
Посмотрите на логику в <Главная/> компонент. будет отображаться только тогда, когда ActiveUserid настоящее.
Прямо сейчас ActiveUserid установлен на null Отказ
Нам нужно убедиться, что ActiveUserid устанавливается всякий раз, когда нажат контакт.
Что вы думаете?
Нам нужно отправить действие, верно?
Ага!
Давайте определим форму действия.
Помните, чем действие – это просто объект с Тип поле и а полезная нагрузка Отказ
Тип Поле обязательно, пока вы можете позвонить полезная нагрузка все, что ты любишь. полезная нагрузка Хотя хорошее имя. Очень распространено тоже.
Таким образом, вот представление о действии:
{
type: "SET_ACTION_ID",
payload: user_id
}Тип или имя действия будут называться Set_action_id Отказ
Если вам было интересно, довольно распространено использование случая змеи с заглавными буквами в типах действий, таких как Set_action_id И не SetConeId или Set-Action-ID Отказ
Кроме того, полезная нагрузка на действие будет user_id пользователя, который будет установлен как активный.
Давайте теперь отправляем действия по взаимодействию пользователя.
Так как это первый раз, когда мы отправляем действия в этом приложении, создайте новый Действия каталог. Пока на этом также создайте Константы папка.
В Константы Папка, создайте новый файл, Action-times.js Отказ
Этот файл имеет исключительную ответственность за сохранение констант типа действий. Я объясню, почему это важно, в ближайшее время.
Напишите следующее в Action-times.js Отказ
Константы/Действия-типы.
export const SET_ACTIVE_USER_ID = "SET_ACTIVE_USER_ID";
Итак, почему это важно?
Чтобы понять это, нам нужно исследовать, когда типы действий используются в приложении Redux.
В большинстве приложений Redux они будут отображаться в двух местах.
1. Редуктор
Когда вы делаете Переключатель За тип действия в ваших редукторах:
switch(action.type) {
case "WITHDRAW_MONEY":
doSomething();
break;
}2. Действие Создатель
В рамках Eaction Creator вы также пишете код, который напоминает это:
export const seWithdrawAmount = amount => ({
type: "WITHDRAW_MONEY,
payload: amount
})Теперь посмотрите на логику «Редуктор» и «Создатель действий» выше. Что общее для обоих?
"Roy_money" нить!
Когда ваша заявка растет, и у вас много этих строк, летящих вокруг места, вы (или кто-то еще), может когда-нибудь сделать ошибку писать "Witddraw_money" или "Roy_mony" вместо "СНЯТЬ ДЕНЬГИ СО СЧЕТА_"
Точка, которую я пытаюсь сделать, это то, что используя сырые строки, такие как это, упрощает опечаток. От опыта, ошибок, которые приходят из опечаток, супер раздражает. Вы можете в конечном итоге искать так долго, только чтобы увидеть, что проблема была вызвана очень маленькой пропуской на вашем конце.
Мешайте себе иметь дело с этим хлопотом.
Хороший способ сделать это, чтобы хранить строки в качестве констант в отдельном файле. Таким образом, вместо того, чтобы писать сырые строки в нескольких местах, вы просто импортируете строку из объявленной константы.
Вы объявляете константы в одном месте, но можете использовать их как можно больше места. Нет опечатки!
Это именно поэтому мы создали Константы/Действия - Типы .JS файл.
Теперь давайте создадим создатель действий.
Действие/index.js.
import { SET_ACTIVE_USER_ID} from "../constants/action-types";
export const setActiveUserId = id => ({
type: SET_ACTIVE_USER_ID,
payload: id
});Как видите, я импортировал строку типа действия из папки констант. Так же, как я объяснил ранее.
Опять же, Action Creator – это просто функция. Я назвал эту функцию SetibledUserid Отказ Это возьмет в себя ID пользователей и вернуть действие (то есть объект) с типом и полезной нагрузкой.
С этим на месте, что осталось, отправляется на это действие, когда пользователь нажимает пользователя и что-то делает с помощью отправленного действия в наших редукторах.
Давайте продолжим двигаться.
Посмотрите на User.js компонент.
Первая строка Возвращение Заявление о Div С именем класса Пользователь :
Это правильное место для настройки обработчика кликов. Как только это Div Нажат, мы отправим действие, которое мы только что создали.
Итак, вот изменение:
И руляркрик Функция прямо здесь:
function handleUserClick({ user_id }) {
store.dispatch(setActiveUserId(user_id));
}Где SetibledUserid был импортирован откуда? Действие Создатель!
import { setActiveUserId } from "../actions";Теперь ниже все User.js Код вы должны иметь в данный момент:
Контейнеры/user.js.
import React from "react";
import "./User.css";
import store from "../store";
import { setActiveUserId } from "../actions";
const User = ({ user }) => {
const { name, profile_pic, status } = user;
return (
{name}
{status}
);
};
function handleUserClick({ user_id }) {
store.dispatch(setActiveUserId(user_id));
}
export default User;Отправить действие, мне также пришлось импортировать магазин и называется методом, store.dispatch () Отказ
Также обратите внимание, что я использовал синтаксис разрезания ES6 для захвата user_id от Пользователь аргумент в руляркрик Отказ
Если вы используете, как я рекомендую, щелкните любой из пользовательских контактов и проверьте журналы. Вы можете добавить консольный журнал в руляркрик нравится:
function handleUserClick({ user_id }) {
console.log(user_id);
store.dispatch(setActiveUserId(user_id));
}Вы найдете зарегистрированный идентификатор пользователя контакта пользователя.
Как вы, возможно, уже заметили, действие отправляется, но на экране ничего не меняется. ActiveUserid не устанавливается в объекте штата. Это потому, что сейчас редукторы ничего не знают о диспетчестве.
Давайте исправим это, но не забудьте удалить console.log (user_id) После проверки журналов.
Посмотрите на ActiveUserid Редуктор:
export default function activeUserId(state = null, action) {
return state;
}Редуктор/ActiveUserid.js.
import { SET_ACTIVE_USER_ID } from "../constants/action-types";
export default function activeUserId(state = null, action) {
switch (action.type) {
case SET_ACTIVE_USER_ID:
return action.payload;
default:
return state;
}
}Вы должны понимать, что здесь происходит.
Первая строка импортирует строку, Set_actaction_user_id Отказ
Затем мы проверяем, пройдено ли действие IS Of Тип Set_actaction_user_id Отказ Если да, то новое значение ActiveUserid установлен на Action.poyload Отказ
Не забывайте, что полезная нагрузка акции содержит user_id пользовательского контакта.
Давайте посмотрим на это в действии. Это работает как ожидалось?
Да!
Теперь ChatWindow Компонент отображается справа ActiveUserid задавать.
В качестве напоминания важно помнить, что с композицией редуктора возвращаемое значение каждого редуктора – это значение поля состояния, которое они представляют, и не весь объект состояния.
Ломая чат внутрь в меньшие компоненты
Посмотрите, что выглядит завершенное окно чата:
Для более зрелищного подхода к развитию я сломал это на три компонента, Заголовок , Чаты и MessageInput :
Итак, чтобы завершить ChatWindow Компонент, мы построим эти три подстегивания. Затем мы составим их, чтобы сформировать ChatWindow компонент.
Готовый?
Начнем с компонента заголовка.
Текущее содержание ChatWindow Компонент это:
import React from "react";
const ChatWindow = ({ activeUserId }) => {
return (
Conversation for user id: {activeUserId}
);
};
export default ChatWindow;Не очень полезно.
Обновите код к этому:
import React from "react";
import store from "../store";
import Header from "../components/Header";
const ChatWindow = ({ activeUserId }) => {
const state = store.getState();
const activeUser = state.contacts[activeUserId];
return (
);
};
export default ChatWindow;Что изменилось?
Помните, что ActiveUserid передается как реквизит в ChatWindow компонент.
Теперь вместо того, чтобы рендеринг текста Разговор для идентификатора пользователя: … , визуализировать Заголовок компонент.
Компонент заголовка не может быть должным образом оказан, без знания пользователей нажатия. Почему?
Имя и Статус оказывается в Заголовок это те из клика пользователя.
Чтобы отслеживать активный пользователь, новую переменную ActiveUser создается, и значение, полученное из объекта состояния, как это: const.contacts [ActiveUserid] Отказ
Как это работает?
Во-первых, мы снимаем государство из магазина Redux: const.getstate () Отказ
Теперь помните, что каждый контакт пользователя приложения хранится в Контакты поле. Кроме того, каждый пользователь сопоставлен их user_id Отказ
Таким образом, активным пользователем может быть получен путем получения пользователя с соответствующим идентификационным полем из Контакты Объект: State.Contacts [ActiveUserid] Отказ
Все хорошо?
На данный момент нам нужно построить оказанные Заголовок компонент.
Создайте файлы, Header.js и Header.css в пределах Компоненты каталог.
Содержание Header.js просто. Вот:
import React from "react";
import "./Header.css";
function Header({ user }) {
const { name, status } = user;
return (
{name}
{status}
);
}
export default Header;Это функциональный компонент без гражданства, который делает Заголовок Элемент и H1 и P Теги, чтобы держать Имя и Статус активного пользователя.
Помните, что активный пользователь является пользователем нажатием с боковой панели.
Стили для <Заголовок/> Компонент одинаково просты. Они здесь:
.Header {
padding: 1rem 2rem;
border-bottom: 1px solid rgba(189, 189, 192, 0.2);
}
.Header__name {
color: #fff;
}Теперь у нас есть этот ребенок, пинающий!
Удивительный. Если вы все еще здесь, у вас действительно здорово!
Давайте перейдем к созданию <Чаты/> компонент.
<Чаты/> Компонент по существу является отображенным списком разговоров пользователя.
Итак, где мы получаем эти разговоры?
Да, из состояния заявления.
Как будто я объяснил ранее, приложение Real World принесет разговоры пользователя с сервера. Тем не менее, мой подход к обучению redux заключается в том, что вы устраняете как можно больше сложностей при изучении основ.
Для этого здесь не будет ресурсов сервера. Мы подключим данные, используя некоторые функции помощника, которые я создал для произвольных данных пользователя данных.
Давайте начнем с подключения необходимых данных в состояние приложения.
Процесс такой же, как мы уже сделали несколько раз.
- Создать редуктор
- Используя ES6, добавьте значение параметра по умолчанию на редуктор
- Включите редуктор в
КоммунаторииФункциональный вызов.
Вы попробуете это, прежде чем перейти к моему решению?
Вот мое решение, в любом случае.
Создать новый файл, messages.js В Редукторы каталог. Это будет редуктор сообщений.
Вот содержание сообщений редуктора.
Редукторы/Messages.js.
import { getMessages } from "../static-data";
export default function messages(state = getMessages(10), action) {
return state;
}Чтобы генерировать случайные сообщения, я импортировал GetMessages Функция из Статические данные
Эта функция принимает сумму, представленную числом. GetMessages Затем функция генерирует это количество сообщений для каждого контакта пользователя.
Например, GetMessages (10) будет генерировать 10 сообщений на контакт пользователя.
Теперь включите редуктор в Коммунатории Вызов функции в Редукторы/index.js.
Редукторы/index.js.
import messages from "./messages";
export default combineReducers({
user,
messages,
contacts,
activeUserId
});Это будет включать в себя Сообщения поле в государственном объекте.
Вот посмотрите на журналы. Теперь вы найдете Сообщения Как видно ниже:
С этим на месте мы можем безопасно возобновить построение Чаты компонент.
Если вы еще этого не сделали, создайте файлы, Chats.js и Chats.css В каталоге компонентов.
Теперь импортируйте Чаты и визуализация ниже <Заголовок/> Компонент в ChatWindow Отказ
Контейнеры/ChatWindow.js.
...
import Chats from "../components/Chats";
...
return (
); <Чаты/> Компонент примет список сообщений из состояния объекта, карта над ними, а затем оказывает их красиво.
Помните, что сообщения прошли в Чаты Специально сообщения для активного пользователя!
Тогда как State.messages Удерживает все сообщения для каждого контакта пользователя, State.messages [ActiveUserid] будет получать сообщения для активного пользователя.
Вот почему каждый разговор сопоставлен с идентификатором пользователя пользователя – для легкого поиска, поскольку мы сделали.
Возьмите активные сообщения пользователя и пропустите их в виде реквизит в Чаты Отказ
Контейнеры/ChatWindow.js.
...
import Chats from "../components/Chats";
...
const activeMsgs = state.messages[activeUserId];
return (
);Теперь помните, что сообщения каждого пользователя – это гигантский объект с каждым сообщением, имеющим номер числа:
Для более легкой итерации и рендеринга мы преобразуем это в массив. Также как мы сделали со списком пользователей в боковой панели.
Для этого нам понадобится Лоташ.
Контейнеры/ChatWindow.js.
...
import _ from "lodash";
import Chats from "../components/Chats";
...
const activeMsgs = state.messages[activeUserId];
return (
);Теперь вместо того, чтобы пройти activemsgs мы проходим в _.values (activemsgs) Отказ
Есть еще один важный шаг, прежде чем мы просматриваем результаты.
Компонент Чаты не был создан.
В Chats.js Напишите следующее. Я объясню потом.
Контейнеры/Chat.js.
import React, { Component } from "react";
import "./Chats.css";
const Chat = ({ message }) => {
const { text, is_user_msg } = message;
return (
{text}
);
};
class Chats extends Component {
render() {
return (
{this.props.messages.map(message => (
))}
);
}
}
export default Chats;Это не слишком много, чтобы понять, но я объясню, что происходит.
Во-первых, посмотрите на Чаты компонент. Вы заметите, что я использовал компонент на основе класса здесь. Вы увидите, почему позже.
В функции рендеринга мы карта над Сообщения реквизит и для каждого сообщение мы вернем Чат компонент.
Чат Компонент супер простой:
const Chat = ({ message }) => {
const { text, is_user_msg } = message;
return (
{text}
);
};Для каждого сообщения, которое передано, текст Содержание сообщения и IS_USER_MSG Флаг оба схватывают с помощью синтаксиса разрушительств ES6, const {text, is_user_msg;
Отчет о возвращении интереснее.
Простой промежуток Тег оказывается.
Отложить некоторые из Jsx Magic, и вот простая форма того, что оказывается:
{text} Текстовое содержимое сообщения завернутся в промежуток элемент. Простой.
Тем не менее, нам нужно дифференцировать между сообщением пользователя приложения и сообщением контакта.
Не забывайте, что разговор случается, по крайней мере, два человека, отправляющих сообщения взад и вперед.
Если сообщение оказывает сообщение пользователя, мы хотим, чтобы оказанную разметку было:
{text} И если нет, мы хотим это:
{text} Обратите внимание, что то, что изменилось, это IS-User-MSG класс переключается.
Таким образом, мы можем конкретно стирать сообщение пользователя, используя селектор CSS, показанный ниже:
.Chat.is-user-msg {
}Итак, именно поэтому у нас есть какое-то фантазия Jsx для оказания названий классов на основе наличия или отсутствия IS_USER_MSG флаг.
{text}Настоящий соус это:
$ {iS_user_msg? “Is-user-msg”: “”
Это тройной оператор прямо там!
Вы можете иметь смысл всего кода в Контейнеры/Chats.js Теперь, да?
Вот результат до сих пор.
Сообщения оказываются, но это не выглядит так хорошо. Это потому, что все сообщения отображаются в промежуток Теги.
С промежуток Метки находятся встроенные элементы, все сообщения просто рендерируют в непрерывной линии, выглядящую скворуту.
Это где мои Homeboy CSS сияют.
Давайте посыпать какую-то степень CSS и получить эту вечеринку:)
Начиная с окна чата, создайте новый файл, Chatwindow.css В Контейнеры каталог.
Не забудьте импортировать его в Chatwindow.js Как это: Импорт "./chatwindow.css"
Напишите это там:
.ChatWindow {
display: flex;
flex-direction: column;
height: 100vh;
}Это удостоверится, что ChatWindow занимает всю доступную высоту, 100ВХ Отказ Я также сделал его сгибным контейнером, чтобы я мог использовать некоторые изгибые вкусности, а именно, а именно, Заголовок , Чаты и Сообщение Отказ
Вы можете увидеть ChatWindow с красной границей ниже:
Давайте перейдем к стайлию Чат Сообщения.
Компоненты/Chats.css.
.Chats {
flex: 1 1 0;
display: flex;
flex-direction: column;
align-items: flex-start;
width: 85%;
margin: 0 auto;
overflow-y: scroll;
}
.Chat {
margin: 1rem 0;
color: #fff;
padding: 1rem;
background: linear-gradient(90deg, #1986d8, #7b9cc2);
max-width: 90%;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.Chat.is-user-msg {
margin-left: auto;
background: #2b2c33;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
@media (min-width: 576px) {
.Chat {
max-width: 60%;
}
}Гоша! Это уже выглядит так хорошо!
Позвольте мне объяснить некоторые важные декларации стиля там.
С Flex: 1 1 0 , .Chats сделано, чтобы расти (принять доступное пространство) и соответственно уменьшитесь в ChatWindow Отказ
.Chats также изготовлен из гибкового контейнера с Дисплей: Flex Отказ Установка Flex-Направление: колонна Все сообщения чата выровнены вертикально. Они больше не встроены элементы, а гибкие предметы!
Чаты, которые не те из пользователей, даны голубой Градиент фона с Фон: линейный градиент (90DEG, # 1986D8, # 7B9CC2);
Это переопределено, если сообщение является пользователем:
.Chat.is-user-msg {
background: #2b2c33;
}Я верю, что вы можете иметь смысл всего остального.
Все идет нормально!
Я действительно взволнован, как далеко мы пришли. Последний шаг, а окно чата полностью построено!
Давайте построим компонент ввода сообщения.
Мы должны были построить более сложные компоненты. Этого не будет трудно построить.
Тем не менее, есть один момент, чтобы рассмотреть.
Входной компонент будет контролируемым компонентом. Поэтому мы будем хранить входное значение в объекте состояния приложения.
Для этого нам понадобится новое поле под названием Набрав в государственном объекте.
Давайте доставим там.
Для наших соображений всякий раз, когда пользовательские типы мы отправим Set_typing_value Тип действия.
Обязательно добавьте эту константу в Константы/Действия – Типы .JS файл:
export const SET_TYPING_VALUE = "SET_TYPING_VALUE";
Кроме того, форма диспетчественного действия будет выглядеть так:
{
type: SET_TYPING_VALUE,
payload: "input value"
}Где . полезная нагрузка Действия – это значение, набранное на входе. Давайте создадим создатель действий для обработки создания этого действия:
Действия/index.js.
import {
SET_ACTIVE_USER_ID,
SET_TYPING_VALUE
} from "../constants/action-types";
…
export const setTypingValue = value => ({
type: SET_TYPING_VALUE,
payload: value
})Теперь давайте создадим новый Набрав Редуктор, который примет эти созданные действия во внимание.
Редукторы/Typing.js.
import { SET_TYPING_VALUE } from "../constants/action-types";
export default function typing(state = "", action) {
switch (action.type) {
case SET_TYPING_VALUE:
return action.payload;
default:
return state;
}
}Значение по умолчанию для поля ввода будет установлено в пустую строку.
Однако, когда действие с типом Set_typing_value Отправляется, значение в полезной нагрузке будет возвращена.
В противном случае состояние по умолчанию "" будет возвращено.
Прежде чем я забуду, обязательно включите этот недавно созданный редуктор в Коммунатории Функциональный вызов.
Редукторы/index.js.
...
import typing from "./typing";
export default combineReducers({
user,
messages,
typing,
contacts,
activeUserId
});Обязательно проверьте журналы и подтвердите, что Набрав поле действительно прикреплено к объекту штата.
Хорошо. Давайте теперь создадим фактический MessageInput компонент. Поскольку этот компонент будет непосредственно говорить на хранилище Redux для настройки и получения его значения ввода, его следует создавать в Контейнеры каталог.
Пока на этом также создайте MessageInput.csss файл тоже.
Контейнеры/MessageInput
import React from "react";
import store from "../store";
import { setTypingValue } from "../actions";
import "./MessageInput.css";
const MessageInput = ({ value }) => {
const handleChange = e => {
store.dispatch(setTypingValue(e.target.value));
};
return (
);
};
export default MessageInput;Ничего магического происходит там.
Всякий раз, когда пользователь ввода в поле ввода, Onchange событие уволено. Это поворот огневает HandleChange функция. HandleChange В свою очередь отправляет settybebalue Действие, которое мы создали ранее. На этот раз, передавая необходимую полезную нагрузку, e.target.value Отказ
Мы создали компонент, но чтобы показать в окне чата, нам нужно включить его в обратный отчет о Chatwindow.js :
...
import MessageInput from "./MessageInput";
const { typing } = state;
return (
);И теперь, у нас есть эта работа!
Но, но это действительно некрасиво:(
Давайте сделаем это красивым.
Контейнеры/messageInput.css.
.Message {
width: 80%;
margin: 1rem auto;
}
.Message__input {
width: 100%;
padding: 1rem;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border: 0;
border-radius: 10px;
font-size: 1rem;
outline: 0;
}Это должно быть достаточно, чтобы сделать волшебство!
Выглядит лучше?
Могу поспорить, это!
Подача формы
Прямо сейчас, когда вы вводите сообщение и нажмите Enter, он не отображается в списке разговоров, а также перезагружает страницу.
Ужасный!
Давайте обрабатываем представление формы.
В MessageInput.js добавить Handlesubmit Обработчик событий, как показано ниже:
......
Подумайте об этом на минуту. Чтобы обновить список сообщений в разговоре … Нам нужно отправить действие!
Это действие необходимо взять ценность В поле ввода и добавьте его к сообщениям активного пользователя.
Хорошо, так выглядит как хорошая форма для действия:
{
type: "SEND_MESSAGE",
payload: {
message,
userId
}
}Понял?
Теперь, давайте напишем Handlesubmit Функция:
//first retrieve the current state object
const state = store.getState();
const handleSubmit = e => {
e.preventDefault();
const { typing, activeUserId } = state;
store.dispatch(sendMessage(typing, activeUserId));
};Вот что происходит в пределах Handlesubmit Функция:
С E.PreventDefault () Я думаю, что вы уже знаете, что это делает. Набрав ценность и ActiveUserid извлечены из Государство Поскольку они оба будут использоваться для создания отправленного действия.
И, наконец, действие отправляется с Store.Dispatch (SendMessage (набрав, ActiveUserid)) Отказ
Упс, но с действием создателем, SendMessage Отказ
В Действия/index.js Создайте SendMessage Действие Создатель:
import {
...
SEND_MESSAGE
} from "../constants/action-types";
export const sendMessage = (message, userId) => ({
type: SEND_MESSAGE,
payload: {
message,
userId
}
})Это также означает Send_message Константа типа действия должна быть создана в Константы/Действия – Типы .JS Отказ
export const SEND_MESSAGE = "SEND_MESSAGE";
Перед тестированием кода вы не должны забывать обновить импорт Action Creator в MessageInput.js включить SendMessage Отказ
import { setTypingValue, sendMessage } from "../actions";Так что попробуй. Работает ли код?
Нет, это не так.
Представлена форма, страница не перезагружается из-за представления формы, действие отправляется, но все равно не обновляются.
Мы ничего не сделали неправильно, за исключением того, что тип действия не был удовлетворен в любом из редукторов.
Редукторы ничего не знают об этом недавно созданном действии типа, Send_message Отказ
Давайте исправить это дальше.
Обновление состояния сообщения
Вот список всех редукторов, которые у нас есть в этот момент:
activeUserId.js contacts.js messages.js typing.js user.js
Что из этого, как вы думаете, должны быть обеспокоены обновлением сообщений в пользовательском разговоре?
Да, Сообщения Редуктор.
Вот текущее содержание Сообщения Редуктор:
import { getMessages } from "../static-data";
export default function messages(state = getMessages(10), action) {
return state;
}Не так много происходит там.
Импорт Send_message Тип действия, и давайте начнем справиться с этим в этом Сообщения Редуктор.
import { getMessages } from "../static-data";
import { SEND_MESSAGE } from "../constants/action-types";
export default function messages(state = getMessages(10), action) {
switch (action.type) {
case SEND_MESSAGE:
return "";
default:
return state;
}
}Теперь мы обрабатываем тип действия, Send_message Но пустая строка возвращается.
Это не то, что мы хотим, но мы построим это отсюда. В то же время, что вы думаете, что является следствием возвращения пустой строки здесь?
Позволь мне показать тебе.
Все сообщения исчезают! Но почему? Это потому, что как только мы попали в Enter, Send_message Действие отправляется. Как только это действие достигает редуктора, редуктор возвращает пустую строку "" Отказ
Таким образом, нет сообщений в государственном объекте. Все прошло!
Это определенно недопустимо.
То, что мы хотим, это сохранить любые сообщения в состоянии. Тем не менее, мы хотим добавить новое сообщение Только к сообщениям активного пользователя.
Хорошо. Но как?
Помните, что у каждого пользователя есть свои сообщения сопоставлены с их идентификатором. Все, что нам нужно сделать, это нацелить этот идентификатор и обновлять только сообщения там.
Вот что это выглядит графически:
Пожалуйста, посмотрите на консоль в графике выше. График предполагает, что пользователь отправил форму ввода три раза с текстом, Привет Отказ
Как ожидалось, текст, Привет Показывает три разных раз в разговорах чата для конкретного контакта.
Теперь посмотрите на консоль. Это даст вам представление о том, что мы стремимся к решению кода.
В этом приложении у каждого пользователя есть 10 сообщений. Каждое из сообщений имеет номер, который варьируется от 0 к 9 Отказ
Таким образом, всякий раз, когда пользователь подает новое сообщение, мы хотим добавить новый сообщение объект, но с увеличением числа!
В консоли в графике выше вы заметите, что число увеличивается. 10 , 11 и 12 Отказ
Кроме того, форма сообщения остается прежней, имея Номер , текст и IS_USER_MSG поля.
{
number: 10,
text: "the text typed",
is_user_msg: true
}IS_USER_MSG всегда будет правдой для этих сообщений. Они приходят от пользователя!
Теперь давайте представим это с некоторым кодом.
Я собираюсь объяснить это хорошо, потому что код может сначала выглядеть комплекс.
Во всяком случае, вот представление в пределах Переключатель блок Сообщения Редуктор:
switch (action.type) {
case SEND_MESSAGE:
const { message, userId } = action.payload;
const allUserMsgs = state[userId];
const number = +_.keys(allUserMsgs).pop() + 1;
return {
...state,
[userId]: {
...allUserMsgs,
[number]: {
number,
text: message,
is_user_msg: true
}
}
};
default:
return state;
}Давайте перейдем через эту строку по линии.
Сразу после Case Send_Message: Мы поддерживаем ссылку на сообщение и UserID передается от действия.
const {message, userId } = action.payloadПродолжать, также важно захватить сообщения активных пользователей. Это сделано на следующей строке с:
const allUserMsgs = state[userId];
Как вы уже можете знать, Государство Здесь не общий государственный объект заявления. Нет. Это государство, управляемое редуктором для Сообщения поле.
Поскольку сообщение каждого контакта отображается со своим идентификатором пользователя, код выше получает сообщения для определенного идентификатора пользователя, передаваемого из действия.
Теперь каждое сообщение имеет Номер Отказ Это действует как уникальный идентификатор некоторых видов. Для входящих сообщений иметь уникальный идентификатор, _.keys (allusermsgs) вернет массив всех ключей сообщений пользователя.
Хорошо, позвольте мне объяснить.
_keys это как Object.keys () Отказ Единственная разница вот что я использую помощник из Лоташ Отказ Вы можете использовать Object.keys () Если хочешь.
Также Allusermsgs это объект, который содержит все сообщения пользователя. Это будет выглядеть что-то подобное:
{
0: {
number: 0,
text: "first message"
is_user_msg: false
},
1: {
number: 0,
text: "first message"
is_user_msg: false
}
}Это будет продолжаться до 10-го сообщения!
Когда мы делаем _.keys (allusermsgs) или Object.keys (allusermsgs) , это вернет массив всех ключей. Что-то вроде этого:
[ 0, 1, 2, 3, 4, 5]
Array.pop () Функция используется для извлечения последнего элемента в массиве. Это самый большой номер, уже существующий для сообщения контакта. Вид как идентификатор сообщения последнего контакта.
Как только это получено, мы добавляем + 1 к этому. Убедитесь, что новое сообщение получает + 1 наибольшего количества доступных сообщений.
Вот весь код, ответственный за это снова:
const number = +_.keys(allUserMsgs).pop() + 1;
Если вам интересно, почему есть + до _ keys (allusermsgs) .pop () + 1 Это, чтобы убедиться, что результат преобразуется в число вместо строки.
Вот и все!
На мясо блока кода:
return {
...state,
[userId]: {
...allUserMsgs,
[number]: {
number,
text: message,
is_user_msg: true
}
}
};Посмотрите внимательно, и я уверен, что вы вызовете из этого.
... Государство Убедитесь, что мы не связываемся с предыдущими сообщениями в приложении.
Поскольку мы используем объектные обозначения, мы можем легко взять сообщение с конкретным идентификатором пользователя с [Логин пользователя]
В объекте мы уверены, что все сообщения пользователя нетронуты: ... allusermsgs.
Наконец, мы добавляем новый объект сообщения с ранее вычисленным номером!
[number]: {
number,
text: message,
is_user_msg: true
}Это может выглядеть сложным, но это не так. Надеюсь, у вас есть опыт работы с такими немотационными вычислениями государства от вашего развития реагирования.
Все еще запутался?
Посмотрите на оператор возврата снова. На этот раз, с некоторыми цветами кода. Это может помочь дышать жизнью в коде:
И что мой друг, это конец обновления разговора, когда введен вклад!
У нас есть всего несколько настроек.
Твики, чтобы сделать общий опыт естественным
Вот как выглядит текущее состояние вещей, когда я пишу Привет! и отправьте три раза.
Вы быстро заметите две проблемы.
- Несмотря на то, что входы отправлены, и сообщения справедливо добавляются к разговорам, я должен прокрутить вниз, чтобы увидеть сообщения. Это не так, как работают приложения для чата. Окно чата должно автоматически прокрутить вниз.
- Было бы неплохо очистить значение ввода при отправлении. Таким образом, пользователь получает некоторую немедленную обратную связь, что их вход был представлен.
Второй гораздо простые исправление. Давайте начнем с этого.
Мы уже отправляем Send_message действие. Мы можем слушать это действие и очистить входное значение в Typing.js Редуктор.
Давайте сделаем только это.
Добавьте это в блоке коммутатора Typing.js Редуктор:
case SEND_MESSAGE:
return "";Который приносит весь код к этому:
Редуктор/Typing.js.
import { SET_TYPING_VALUE, SEND_MESSAGE } from "../constants/action-types";
export default function typing(state = "", action) {
switch (action.type) {
case SET_TYPING_VALUE:
return action.payload;
case SEND_MESSAGE:
return "";
default:
return state;
}
}Теперь, как только действие получает здесь, Набрав Значение будет очищено, а пустая строка будет возвращена.
Вот что в действии:
Оно работает!
Как и ожидалось, входное значение теперь очищено.
Хорошо, давайте убедитесь, что окно чата прокручиваются при обновлении.
Для этого нам понадобится немного манипуляций DOM. Вот почему я настаивал на создании <Чаты/> Компонент класса.
Хорошо, давайте поговорим код.
Во-первых, нам нужно создать Ref держать узел Chats DOM.
constructor(props) {
super(props);
this.chatsRef = React.createRef();
}Если вы не знакомы с Rect.Createref () , это совершенно нормально. Это потому, что Regact 16 представил A Новый способ создания Refs Отказ
Мы поддерживаем ссылку на этот Ref через Это.chatsref Отказ
В визуализации DOM мы тогда обновляем следующее:
Теперь у нас есть ссылка на Div это держит все разговоры в чате.
Давайте убедитесь, что это всегда прокручивается до дна при обновлении.
Скажи привет к методам жизненного цикла!
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}Итак, как только компонент крепится, мы вызываем Scrolltobottom функция. Мы делаем то же самое, когда приложение тоже обновляется!
Теперь, вот Scrolltobottom Функция:
scrollToBottom = () => {
this.chatsRef.current.scrollTop = this.chatsRef.current.scrollHeight;
};Все, что мы делаем, это обновление Scrolltop Свойство, чтобы соответствовать пособие
Не так сложно. this.chatsref.current Относится к рассматриваемому узлу DOM.
Вот весь код для Chats.js на этой точке.
...
class Chats extends Component {
constructor(props) {
super(props);
this.chatsRef = React.createRef();
}
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}
scrollToBottom = () => {
this.chatsRef.current.scrollTop = this.chatsRef.current.scrollHeight;
};
render() {
return (
{this.props.messages.map(message => (
))}
);
}
}
export default Chats;Привет! С этим у нас есть Skypey, работая как ожидалось!
Вот демонстрация. Обратите внимание, как обновляется положение положения прокрутки, как только компонент устанавливает, а при набираемой наведении сочетания компонент также обновляется.
Потрясающие вещи!
Итак, взволнован!
Мы нашли так далеко:)
Заключение и резюме
О, мой! Это был удивительный опыт для меня. Строительство Skypey было очень весело.
Ты любил это? Я хотел бы увидеть вашу собственную версию Skype. Измените цвета, настраивайте дизайн и постройте что-то лучшее!
Когда вы закончите, Пришлите мне твит И я буду рад подбодрить тебя.
Вот краткое изложение некоторых из вещей, которые мы узнали до сих пор:
- Это хорошая практика, чтобы всегда планировать процесс разработки вашего приложения перед прыжками в код.
- В вашем государственном объекте избегайте вложенных объектов вообще стоимость. Держите объект состояния нормализованным.
- Хранение ваших государственных полей в качестве объектов имеет некоторые преимущества. Будьте одинаково осведомлены о проблемах с использованием объектов, в основном отсутствием порядка.
-
ЛоташУтилита библиотеки приходит очень удобно, если вы решите использовать объекты над массивами в вашем объекте штата. - Независимо от того, насколько мало, всегда занимаем некоторое время для разработки государственного объекта вашего приложения.
- С Redux вам не всегда приходится пропускать реквизиты. Вы можете получить доступ к значениям состояния напрямую из магазина.
- Всегда держите аккуратную структуру папки в вашем приложениях Redux, например, все основные актеры Redux в своих собственных папках. Помимо аккуратной общей структуры кода, это облегчает другим людям сотрудничать в вашем проекте, поскольку они, скорее всего, отличаются одной и той же структурой папки.
- Состав редуктора действительно велик, особенно как ваше приложение растет. Это повышает оправданность и уменьшает тенденцию к трудностями к ошибкам.
- Для композиции редуктора используют
Коммунаторииотreduxбиблиотека. - Объект, переданный в
КоммунаторииФункция предназначена для напоминания состояния вашего приложения, причем каждое значение получено из соответствующих редукторов. - Всегда ломайте большие компоненты в меньшие управляемые биты. Это намного легче построить свой путь так.
Увидимся!
Упражнения
Приложение Skypey, которое мы построили здесь, не все, что в приложении. Есть еще две задачи для вас.
- Расширить приложение Skypey, которое мы создали для обработки редактирования сообщения пользователя, как показано ниже.
- Расширить приложение Skypey, которое мы создали, чтобы также обрабатывать удаление сообщения пользователя. Так же, как показано ниже.
Это должно быть весело реализовать!
Глава 5: Что дальше?
Книга, которую вы в настоящее время читаете, это один из трех в режиме redux Trio Sequel.
Во второй книге, понимая redux 2, я объясняю подробному подробному сложным расширенным концепциям Redux, такие как Cделительными гостями, компоненты более высокого порядка, создавая вызовы AJAX и многое другое.
Там не заканчивается.
Я также покажу вам некоторых из самых любимых библиотек сообщества Redux для решения распространенных проблем. Redulect, Redux-Form, Redux-Thunk, пересчитаю и многое другое.
Следующий раздел – это выдержка, Понимание Redux 2 Отказ
Как приятно.
Готовый?
Я глубоко покрываю это в следующей книге, Понимание Redux 2 Отказ
И много больше!
До этого я поймаю тебя позже!
Эй, продолжайте кодирование!
Много любви ??