Я создам небольшое приложение для простых рейтинговых вопросов. Это задумано как упражнение для React и Redux, так как я все еще не понимаю его.

➡️ Github Repo доступен здесь ⬅️

📄 Содержание

«Все на практике».

- Пеле

Мотивация для этой статьи

Еще одно небольшое приложение для понимания Redux и React. Такое ощущение, что это сотое приложение, пытающееся понять Redux. Но 1 месяц без Redux, и вы снова начинаете практически ни с чего. Я такой: «Да, я слышал об этом» - и все. Действие, Создатели действий, Редукторы, Диспетчеризация, блабла. Слишком много вещей, чтобы понять: D Итак, еще раз ↗️

Модульность базы

Структурируйте компоненты так, чтобы они идеально вписывались в приложение Redux.

➡️ Кодовая база на Github ⬅️

  • компонент секундомера имеет собственное локальное состояние, не зависит от других компонентов
  • компоненты статистики и счетчика зависят от других компонентов
  • AddQuestionForm зависит от других компонентов и также содержит логическую информацию
  • компоненты заголовка и вопроса

Модуляризация помогает

  • разделить обязанности, что означает более легкое тестирование и отладку
  • лучше масштабировать приложение и проще использовать Redux
  • лучше организовать между командами

➡️ Модульный код на Github ⬅️

Добавление Redux

Типы действий

Решите, какие компоненты должны участвовать в магазине Redux. - ›В этом приложении для всех компонентов должны быть доступны только вопросы.

Узнайте, какие события происходят в вашем приложении для этого конкретного состояния. - ›В этом приложении это

  • изменение счета
  • добавление вопросов
  • удаление вопросов

Редукторы

Редукторы - это чистые функции, которые изменяют состояние в соответствии с типом действия.

Функция reducer предоставляет различные операторы switch о том, как изменить состояние. (Никогда не меняйте само состояние! Это должна быть чистая функция! # Неизменяемость)

Например:

export default function Player(state = initialState, action) {
  switch (action.type) {
    case QuestionActionTypes.ADD_PLAYER:
      return [
        ...state,
        {
          name: action.name,
          score: 0,
        },
      ];
    case QuestionActionTypes.REMOVE_QUESTION:
      return [...state.slice(0, action.index), ...state.sclice(action.index + 1)];
    case QuestionActionTypes.UPDATE_QUESTION_SCORE:
      return state.map((question, index) => {
        if (index === action.index) {
          return {
            ...question,
            score: question.score + question.score,
          };
        }
        return question;
      });
    default:
      return state;
  }
}

Действия и Создатели действий

Отправка действия в Redux

  • создатели действий генерируют действие (действие = событие, которое приведет к изменению состояния)
  • действие отправляется в магазин Redux
  • редуктор передает действие компоненту и возвращает новое состояние

Например, для добавления вопроса:

export const addQuestion = name => ({
  type: QuestionActionTypes.ADD_QUESTION,
  name,
});

Создать Redux Store

Создайте хранилище в своем index.js, передав ему основной редуктор и оберните его вокруг компонента табло, чтобы предоставить хранилище всему приложению.

Подключите контейнер к магазину

  • используйте mapStateToProps, чтобы присвоить состояние значению свойства - ›назначить состояние вопросов в качестве свойства
  • для автоматической отправки созданных действий используйте:
const {dispatch, questions} = this.props;
const addQuestion = bindActionCreators(QuestionActionCreators.addQuestion, dispatch);
const removeQuestion = bindActionCreators(QuestionActionCreators.removeQuestion, dispatch);
const updateQuestionScore = bindActionCreators(QuestionActionCreators.updateQuestionScore, dispatch);
  • обновите обработчики событий на компонентах соответственно (компоненты счетчика, вопроса и табло)
  • компоненты заголовка и секундомера не нуждаются в изменениях, потому что они не участвуют в цикле Redux

Добавьте еще один компонент в приложение Redux

Теперь мы хотим отображать детали для каждого вопроса.

  • добавить новый тип действия (выбрать вопрос)
  • расширить редуктор новым корпусом переключателя и дополнительным состоянием
  • добавить новый создатель действий для выбора вопроса
  • создать новый bindActionCreator в компоненте табло
  • обновить mapStateToProps с выбранным индексом вопроса
  • создать компонент QuestionDetail для отображения деталей
  • обновить обработчик событий в компоненте вопроса

➡️ Смотрите коммит с реализацией компонента detail на Github ⬅️

Реализовать уток

Для небольших приложений концепция уток может помочь быстрее разработать приложение Redux. По сути, вместо того, чтобы сохранять все модульное (действия, редукторы, actionCreators), мы также можем хранить их в одном файле, чтобы иметь лучший обзор.

Этот файл выглядит так:

// Actions
const ADD_QUESTION = 'question/ADD_QUESTION';
const REMOVE_QUESTION = 'question/REMOVE_QUESTION';
const UPDATE_QUESTION_SCORE = 'question/UPDATE_QUESTION_SCORE';
const SELECT_QUESTION = 'question/SELECT_QUESTION';
// Reducers
const initialState = {
  questions: [
    {
      name: 'Do you like AI?',
      score: 31,
      created: '00:00',
      updated: '00:00',
    },
    {
      name: 'Do you like Engineering?',
      score: 20,
      created: '00:00',
      updated: '00:00',
    },
    {
      name: 'How many Redux Apps?',
      score: 50,
      created: '00:00',
      updated: '00:00',
    },
  ],
  selectedQuestionIndex: -1,
};
export default function Question(state = initialState, action) {
  const date = `${new Date().getHours()}:00`;
  switch (action.type) {
    case ADD_QUESTION:
      const addQuestionList = [
        ...state.questions,
        {
          name: action.name,
          score: 0,
          created: date,
        },
      ];
      return {
        ...state,
        questions: addQuestionList,
      };
    case REMOVE_QUESTION:
      const removeQuestionList = [
        ...state.questions.slice(0, action.index),
        ...state.questions.slice(action.index + 1),
      ];
      return {
        ...state,
        questions: removeQuestionList,
      };
    case UPDATE_QUESTION_SCORE:
      const updateQuestionList = state.questions.map((question, index) => {
        if (index === action.index) {
          return {
            ...question,
            score: question.score + action.score,
            updated: date,
          };
        }
        return question;
      });
      return {
        ...state,
        questions: updateQuestionList,
      };
    case SELECT_QUESTION:
      return {
        ...state,
        selectedQuestionIndex: action.index,
      };
    default:
      return state;
  }
}
// ActionCreators
export const addQuestion = name => ({
  type: ADD_QUESTION,
  name,
});
export const removeQuestion = index => ({
  type: REMOVE_QUESTION,
  index,
});
export const updateQuestionScore = (index, score) => ({
  type: UPDATE_QUESTION_SCORE,
  index,
  score,
});
export const selectQuestion = index => ({
  type: SELECT_QUESTION,
  index,
});

➡️ Смотрите коммит с реализацией уток на Github ⬅️

Инструменты разработчика Chrome Redux

const store = createStore(
	QuestionReducer,
	window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
);

DevTools помогает разрабатывать и отлаживать ваше приложение Redux. Ознакомьтесь с этой статьей, чтобы узнать больше.

➡️ Результат на Github ⬅️

Если вы что-то узнали из этой статьи, дайте мне знать в комментариях или сердцах. Не забудьте подписаться на больше :)