Это руководство научит вас создавать React
среду и начать разработку с react
, webpack
и sass
. В этом руководстве мы не будем использовать create-react-app
cli, вместо этого мы создадим среду react dev с нуля.
Сначала мы установим webpack
и произведем минимальную настройку. Затем мы создадим простой React
компонент. После этого разберемся с Redux
. Наконец, мы можем написать некоторые правила стиля для компонента приложения с SASS
и настроить загрузчики веб-пакетов для SASS
объединения.
Предварительно требования:
Webpack
Создайте каталог проекта и двигайтесь по нему.
mkdir react-setup cd react-setup
Критский проект по пряжи:
yarn init -y
Или npm:
npm init -y
Установите библиотеки webpack
и webpack-dev-server
.
yarn add --dev webpack webpack-cli webpack-dev-server
Создайте каталог src
и создайте в нем файл index.js
. Поместите код в src/index.js
файл.
const foo = () => console.warn('OK'); foo();
Создайте webpack.config.js file
в корне проекта.
Концепции конфигурации Webpack
Файл конфигурации содержит четыре основных раздела:
Entry
- точка входа модуля, который вы хотите связать.Output
- указывает веб-пакет, куда помещать обрабатываемые бандлы.Modules
- массив загрузчиков.Plugins
- массив плагинов, решающих другие задачи.
Вход
В webpack.config.js
определите ключ входа в объект экспорта.
module.exports = { entry: './src/index.js' };
Как видите, src/index.js
файл, который вы создали ранее, является точкой входа в ваш модуль.
Выход
Определите выходной ключ в объекте конфигурации.
const path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve('./dist'), filename: 'bundle.js' } };
path
- встроенный модуль nodeJs предоставляет утилиты для работы с путями к файлам и каталогам.
После объединения выходной файл будет помещен в каталог dist
.
Обновите свой package.json
файл, напишите в нем раздел scripts
.
{ "name": "react-setup", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "dev": "webpack" }, "devDependencies": { "webpack": "^4.5.0", "webpack-cli": "^2.0.14", "webpack-dev-server": "^3.1.3" } }
Модуль
Пора прикрепить загрузчики к config.module
объекту.
Сначала установите babel-cli
и babel-loader
:
yarn add babel-cli babel-loader
После завершения установки прикрепите babel-loader
к массиву module.rules
в конфигурации webpack.
const path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve('./dist'), filename: 'bundle.js' }, module: { rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ } ] } };
Плагины
Установите html-webpack-plugin
, который генерирует простой html
шаблон в свой проект, и включите в него ваше связанное приложение.
yarn add html-webpack-plugin
Создайте template.html
файл в корне проекта и вставьте код удара.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"></div> </body> </html>
Поместите html-webpack-plugin
в plugins
массив объекта конфигурации webpack. Установите опцию шаблона для конфигурации HtmlWebpackPlugin
.
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // Entry point entry: './src/index.js', // Output dist output: { path: path.resolve('./dist'), filename: 'bundle.js' }, // Loaders setup module: { rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ } ] }, // Plugins... plugins: [ new HtmlWebpackPlugin({ template: 'template.html' }) ] };
Запустите команду yarn dev
, которая построит ваш модуль, и поместите вывод в папку dist
. После завершения сборки перейдите в каталог dist
и откройте файл index.html
в браузере, затем откройте консоль, и вы должны увидеть предупреждение «ОК» в консоли.
Сервер разработки Webpack
Пришло время настроить сервер разработки, чтобы обеспечить перезагрузку в реальном времени после редактирования кода. Отредактируйте webpack.cofing.js
файл.
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // Entry point entry: './src/index.js', // Output dist output: { path: path.resolve('./dist'), filename: 'bundle.js' }, // devServer configure devServer: { contentBase: path.join(__dirname, 'dist'), compress: true, port: 8080 }, // Loaders setup module: { rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ } ] }, // Plugins... plugins: [ new HtmlWebpackPlugin({ template: 'template.html' }) ] };
Добавьте start
скрипт в раздел скриптов package.json
файла.
{ "name": "react-setup", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "start": "webpack-dev-server", "dev": "webpack" }, "dependencies": { "babel-cli": "^6.26.0", "babel-loader": "^7.1.4", "html-webpack-plugin": "^3.2.0" }, "devDependencies": { "webpack": "^4.5.0", "webpack-cli": "^2.0.14", "webpack-dev-server": "^3.1.3" } }
Запустите команду yarn start
в терминале, откройте браузер и перейдите к localhost:8080
. После этого немного отредактируйте код src/index.js
файла, и вы увидите автоматическую перезагрузку в вашем браузере.
Реагировать
Установите в проект библиотеки react
и react-dom
.
yarn add react react-dom
Создайте файл App.js
в каталоге src/components
и напишите туда свой первый простой компонент React.
import React from 'react'; export default () => <h1>Hello!</h1>;
Чем нужно рендерить App
компонент в dom. Переместитесь в src/index.js
file и увлажните компонент App
.
import React from 'react'; import { hydrate } from 'react-dom'; import App from './components/App'; hydrate( <App />, document.querySelector('#app') );
Сохраните файл, и вы увидите ошибку в консоли браузера и в терминале, например:
Эта ошибка возникает из-за того, что в проекте не установлена предустановка babel react. Перейдите к установке пресета Babel React и Babel preset es2015 в свой проект, а также стадий пресетов.
yarn add babel-preset-react babel-preset-es2015 babel-preset-stage-0 babel-preset-stage-1 babel-preset-stage-2
После установки пресетов создайте файл .babelrc
в корне проекта и объявите в нем установленные пресеты.
{ "presets": ["react", "es2015", "stage-0", "stage-1", "stage-2"] }
Снова запустите команду yarn start
, перейдите к localhost:8080
, и вы увидите компонент App
в DOM.
Redux
Для использования redux необходимо установить пару библиотек redux. Фактически redux
, reduxThunk
промежуточное ПО для асинхронных действий и react-redux
для передачи частей состояния redux для реагирования компонентов
yarn add redux redux-thunk react-redux
Создайте файл people.js
в папке src/reducers
, это будет ваш первый редуктор с простым шаблоном без обработки каких-либо типов действий.
const INITIAL_STATE = { isFetching: false, data: [] }; export default (state = INITIAL_STATE, action) => { switch (action.type) { default: return state; } }
После этого создайте index.js
файл в src/reducers
, это будет ваш rootReducer
.
import { combineReducers } from 'redux'; import People from './people'; export default combineReducers({ people: People });
Осталось подключить rootReducer
реагирующее приложение. Откройте файл src/index.js
и напишите приведенный ниже код для его достижения.
import React from 'react'; import { hydrate } from 'react-dom'; import App from './components/App'; import { Provider } from 'react-redux'; import { createStore, applyMiddleware } from 'redux'; import reduxThunk from 'redux-thunk'; import rootReducer from './reducers' const store = createStore(rootReducer, applyMiddleware(reduxThunk)); hydrate( <Provider store={store}> <App /> </Provider>, document.querySelector('#app') );
Если вы не видите ошибок, все в порядке. Переместитесь к App
компоненту и прикрепите к компоненту people
фрагмент хранилища.
import React, { Component } from 'react'; import { connect } from 'react-redux'; class App extends Component { render() { console.log(this.props); return <h1>Hello</h1>; } } const mapStateToProps = ({ people }) => ({ people }); export default connect(mapStateToProps)(App);
Запустите команду yarn start
в своем терминале, затем переключитесь в браузер, и в консоли браузера вы увидите данные о людях в реквизитах компонента.
Действия
Пришло время оценить реальную выборку. Я использую SWAPI для игры.
Создайте файл types.js
в каталоге src/actions
, чтобы объявить типы действий приложения.
export const REQUEST_FETCH_PEOPLE = 'REQUEST_FETCH_PEOPLE'; export const RECEIVE_FETCH_PEOPLE = 'RECEIVE_FETCH_PEOPLE';
Я также axios, чтобы упростить выборку данных.
yarn add axios
Создайте people.js
файл в каталоге src/actions
и напишите действие fetchPeople
.
import axios from 'axios'; import { REQUEST_FETCH_PEOPLE, RECEIVE_FETCH_PEOPLE } from './types'; export const fetchPeople = () => dispatch => { dispatch({ type: REQUEST_FETCH_PEOPLE }); axios.get('https://swapi.co/api/people/') .then(res => dispatch({ type: RECEIVE_FETCH_PEOPLE, payload: res.data.results })); };
Это действие отправляет некоторые типы действий, которые вы импортируете из ./types.js
файла. Необходимо для обработки этого типа действий people
reducer. Перейдите к src/reducers/people.js
и измените reducer для обработки типов актина.
import { REQUEST_FETCH_PEOPLE, RECEIVE_FETCH_PEOPLE } from '../actions/types'; const INITIAL_STATE = { isFetching: false, data: [] }; export default (state = INITIAL_STATE, action) => { switch (action.type) { case REQUEST_FETCH_PEOPLE: { return { ...state, isFetching: true }; } case RECEIVE_FETCH_PEOPLE: { return { ...state, isFetching: false, data: action.payload }; } default: return state; } }
После этого вы можете вызвать действие fetchPeople
из App
компонента. Откройте действие src/components/App.js file
присоедините fetchPeople
к функции connect
и напишите ловушку componentDidMount
.
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { fetchPeople } from "../actions/people"; class App extends Component { componentDidMount() { this.props.fetchPeople(); } render() { console.log(this.props); return <h1>Hello</h1>; } } const mapStateToProps = ({ people }) => ({ people }); export default connect(mapStateToProps, { fetchPeople })(App);
Переключитесь в консоль браузера и посмотрите тройной журнал данных о людях. В последнем журнале вы можете видеть, что значение ключа data
содержит 10 элементов, это означает, что выборка работает нормально.
Прежде чем мы перейдем к разделу стилей, давайте добавим некоторый шаблон html в компонент App
.
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { fetchPeople } from "../actions/people"; class App extends Component { componentDidMount() { this.props.fetchPeople(); } render() { const { isFetching, data } = this.props.people; if(isFetching) { return <span>Loading...</span> } return <div className="container"> <ul className="people"> {data.map(item => <li key={item.name}> <span>Name: {item.name}</span> <span>Height: {item.height}</span> </li>)} </ul> </div>; } } const mapStateToProps = ({ people }) => ({ people }); export default connect(mapStateToProps, { fetchPeople })(App);
После этого посмотрите на вкладку вашего браузера и увидите там список людей.
SASS
Чтобы добавить несколько стилей, создайте каталог scss
в корне проекта и создайте там файл main.scss
. Добавьте некоторые правила стиля в scss/main.scss
файл.
body { margin: 0; padding: 0; } .container { max-width: 800px; padding: 0 16px; margin: 48px auto; } ul.people { list-style: none; margin: 0; padding: 0; li { list-style: none; padding: 4px; margin: 0; display: flex; flex-direction: column; justify-content: flex-start; align-items: flex-start; border-bottom: 1px solid #34495e; transition: box-shadow .2s ease-in-out; span { color: #2c3e50; &:first-child { color: #3498db; margin-bottom: 4px; } } &:hover { box-shadow: 0 4px 8px rgba(0,0,0, .12); } } }
Импортировать sass в начало файла App.js
.
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { fetchPeople } from "../actions/people"; import '../../scss/main.scss'; class App extends Component { ... }
После объединения вы увидите такую ошибку синтаксического анализа:
Последнее, что мы сделаем, это настроим загрузчики стилей в разделе rules
файла конфигурации webpack. Сначала установите его.
yarn add style-loader css-loader sass-loader node-sass
После завершения установки создайте правило nu в разделе module.rules
в конфигурации webpack и поместите его туда. Наконец, ваш webpack.config.js
файл должен выглядеть так.
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // Entry point entry: './src/index.js', // Output dist output: { path: path.resolve('./dist'), filename: 'bundle.js' }, // devServer configure devServer: { contentBase: path.join(__dirname, 'dist'), compress: true, port: 8080 }, // Loaders setup module: { rules: [ // Rules for js babel { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }, // Rules for css node-sass { test: /\.scss$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'sass-loader' }, ] } ] }, // Plugins... plugins: [ new HtmlWebpackPlugin({ template: 'template.html' }) ] };
Вернитесь в свой браузер, и вы увидите стилизованный компонент приложения.
Если ошибок нет, значит все в порядке.
Это все
Вы создали приложение React с управлением магазином redux. Сделано чистым, чтобы понимать конфигурацию веб-пакетов, выборку данных, компиляцию стилей.
Если у вас есть какие-либо вопросы или вы где-то застряли, не стесняйтесь писать ответы, и я отвечу вам, как только смогу.
Код этого проекта хранится в моем репозитории на github.
Спасибо.