Сокращение шаблона приложения React/Redux с помощью require.context и структуры модуля
require.context позволяет нам импортировать несколько файлов, используя регулярное выражение
Гонсало ПоццоЗаблокированоUnblockFollowFollowing
20 октября 2018 г.
Когда приложение React/Redux растет, мы понимаем, что есть процессы, которые становятся очень повторяющимися, например, добавление наших редьюсеров к корневому редьюсеру.
Структура каталогов — одна из самых важных вещей для хорошей организации нашего приложения, это позволит нам легко находить файлы, не иметь проблем с их именами и быть уверенным в ответственности, которую должен нести каждый компонент в отношении своей полезности.
Вот почему сегодня мы собираемся сосредоточиться на этих двух моментах.
Для этого мы создадим очень простое приложение, над которым будут шутить этот API каждый раз, когда мы нажимаем кнопку, они будут перечислены вместе с кнопкой для удаления каждой шутки по отдельности.
Создание нашего приложения
Первое, что мы собираемся сделать, это создать новое приложение, используя создать-реагировать-приложение
npx create-react-app reducing-boilerplate
Давайте запустим наше приложение, чтобы убедиться, что все работает правильно.
Мы в папке reducing-boilerplate
который создал приложение create-реагировать, и мы запускаем:
npm start
В браузере откроется новая вкладка, и мы увидим следующий экран:
Приложение работает на
Создаем наш первый модуль
Мы можем думать о модуле как о группе функций, когда мы можем убедиться, что все, что в нем содержится, принадлежит тому, на что указывает его имя.
У нас будут редукторы, помощники API и компоненты, которые имеют отношение к шуткам, кажется, это хорошая возможность создать módulo
модули
Давайте создадим папку modules
в src.
Внутри мы создадим папку joke
Модули названы в единственном числе, так как это относится к функциональности независимо от количества.
В пределах joke
давайте создадим файлы api.js
, reducers.js
и папка components
с файлом JokesManager.js
наша папка modules
это будет выглядеть так:
.└── modules/ └── joke/ ├── api.js ├── reducers.js └── components/ └── JokesManager.js
На данный момент наши файлы будут пустыми, но мы вернемся к этому позже.
Установка и настройка Redux
Установим необходимые зависимости:
npm install redux react-redux --save
Мы создаем папку db
в пределах src
с файлами reducers.js
(наш корневой редуктор), store.js
(редукционная конфигурация), utils.js
(утилита, которую мы увидим через некоторое время).
.└── db/ ├── store.js ├── reducers.js └── utils.js
/db/utils.js
requireAll
отвечает за извлечение необходимой нам информации из того, что он возвращает require.context
export const requireAll = ctx =>
ctx
.keys()
.map(ctx)
.map(m => m.default)
.filter(Boolean);
Сильно разбирать нет смысла, так как это почти копипаста документации вебпака
БД/reducers.js
Это будет перебирать папку modules
и все его подкаталоги в поисках файлов с именем reducers.js
и объединит их в один объект. Это означает, что каждый раз, когда мы создаем модуль и добавляем новый файл reducers.js
нам не придется вручную добавлять его в наш корневой редуктор!
import {requireAll} from "./utils";
export default Object.assign(
{},
...requireAll(require.context("../modules", true, /reducers\.js$/))
);
Если бы мы хотели добавить еще один редуктор вручную, мы могли бы сделать это, добавив новую запись в
Object.assign
БД/store.js
Мы создаем редукционный магазин, используя наш корневой редуктор
import {createStore, combineReducers} from "redux";
import reducers from "./reducers";
export default createStore(combineReducers(reducers));
index.js
Мы собираемся обернуть все наше приложение Provider
из react-redux, проходящего через props, магазин, который мы только что создали:
import React from "react";
import ReactDOM from "react-dom";
import {Provider} from "react-redux";
import App from "./App";
import store from "./db/store";
import "./index.css";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
Внедрение нашего модуля
Мы собираемся добавить содержимое в файлы, которые мы ранее создали в нашем модуле.
модули/шутка/api.js
Он будет отвечать за получение информации из API и преобразование ее во что-то, что мы можем использовать из нашего компонента.
const URL = "
export default {
random: {
fetch: () =>
fetch(`${URL}/random`)
.then(res => res.json())
.then(joke => joke.value)
}
};
мы используем
fetch
родной браузер и обещания для простоты, но вы можете использовать асинхронно/ожидание или что вы предпочитаете.
/modules/шутка/reducers.js
Наше приложение может:
- Запустите запрос API, который отключит кнопку получения шутки.
- Добавьте в список новую шутку, которая снова активирует кнопку «Получить шутку».
- Удалить шутку из списка.
const initialState = {
joke: {
status: "init",
list: []
}
};
export default {
joke: (state = initialState.joke, action) => {
switch (action.type) {
case "FETCH_JOKE": {
return {
...state,
status: "pending"
};
}
case "ADD_JOKE": {
return {
...state,
list: state.list.concat(action.payload),
status: "init"
};
}
case "DELETE_JOKE": {
return {
...state,
list: state.list.filter(joke => joke !== action.payload)
};
}
default:
return state;
}
}
};
Чтобы добавить больше редукторов в тот же модуль, мы можем добавить больше элементов в объект, который мы экспортируем:
export default {
joke: (state, action) => ...,
selectedJoke: (state, action) => ...
}
Если вам не нравится иметь несколько редукторов в одном файле, вы можете создать их внутри папки.
reducers
и импортировать их вreducer.js
модули/шутка/компоненты/JokesManager.js
Наш компонент будет:
- Показать список шуток
- Есть кнопка для удаления каждой шутки
- Есть кнопка, чтобы получить новую шутку
import React from "react";
import {connect} from "react-redux";
import jokeApi from "../api";
const JokesManager = ({jokes, loading, getJoke, deleteJoke}) => (
<div>
<ul>
{jokes.map(joke => (
<li key={joke}>
{joke}
<button type="button" onClick={() => deleteJoke(joke)}>
Delete
</button>
</li>
))}
</ul>
<button type="button" onClick={getJoke} disabled={loading}>
Get joke
</button>
</div>
);
export default connect(
({joke}) => ({
jokes: joke.list,
loading: joke.status === "pending"
}),
dispatch => ({
getJoke: () => {
dispatch({type: "FETCH_JOKE"});
return jokeApi.random
.fetch()
.then(joke => dispatch({type: "ADD_JOKE", payload: joke}));
},
deleteJoke: joke => dispatch({type: "DELETE_JOKE", payload: joke}),
})
)(JokesManager);
С помощью нашего модуля
Давайте использовать JokesManager
в нашем приложении.
App.js
import React from "react";
import JokesManager from "./modules/joke/components/JokesManager";
const App = () => (
<div>
<h1>Chistes de Chuck Norris</h1>
<JokesManager />
</div>
);
export default App;
И конечный результат:
Большой!
Ресурсы
Другой
- Мы создаем наше приложение с помощью create-react-app.
- Мы создали модуль и необходимые нам файлы.
- Добавляем и настраиваем Redux с помощью
require.context
- Мы используем наш модуль в приложении.
Если вам понравилось или было полезно, поделитесь с тем, кому это может быть полезно, если вам что-то показалось не так, скажите!