Это вводная статья, посвященная редуксу, для получения дополнительной информации см.официальная документация.
В этой статье будет реализован небольшой пример счетчика, который слишком прост, чтобы дышать, тремя способами: сначала используйте React для его реализации, а затем медленно вводите содержимое Redux, чтобы понять, что такое Redux, зачем использовать Redux и как его использовать. используйте Redux просто.
1. React реализует счетчик
Приведенный выше пример очень просто реализовать с помощью React: инициализируйте приложение creact-react-app, а затем, чтобы страница выглядела красивее, добавьте CDN bootstrap в index.html и измените App.js следующим образом: .
<link href="https://cdn.bootcss.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet">
import React, { Component } from 'react';
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
count: 0
}
}
handleIncrement = () => {
this.setState({
count: this.state.count + 1
})
}
handleDecrement = () => {
this.setState({
count: this.state.count - 1
})
}
render() {
return (
<div className="container">
<h1 className="text-center mt-5">{this.state.count}</h1>
<p className="text-center">
<button onClick={this.handleIncrement} className="btn btn-primary mr-2">Increase</button>
<button onClick={this.handleDecrement} className="btn btn-danger my-2">Decrease</button>
</p>
</div>
);
}
}
Этот пример очень простой, но мы должны подумать о том, как React может изменить это число.
Есть два ключевых шага: во-первых, он считывает начальное значение из состояния, а затем, когда происходит событие щелчка, он вызывает метод setState для изменения значения состояния и повторной визуализации страницы. Таким образом, вы можете увидеть эффект изменения чисел на странице.
Итак, вот проблема: для хранения данных в компоненте в React требуется только состояние и setState. Что делать, если несколько компонентов должны поддерживать эти данные?
2. Зачем использовать Redux
Любой, кто знает, как передавать данные между компонентами React, должен знать, что React передает данные уровень за уровнем. Как и на левом рисунке ниже, если зеленый компонент хочет передать данные в определенное время красному компоненту, ему нужно дважды перезвонить, а затем загрузить их один раз, что очень хлопотно.
И как это делает Redux? Очень важной частью Redux является Store. Данные, управляемые в Store, не зависят от компонента React. Если определенные данные в компоненте React изменяются в определенное время (это можно назвать If статус изменился), вы можете напрямую изменить данные, управляемые в этом хранилище, чтобы другие компоненты могли напрямую получать данные в это время, не передавая их туда и обратно.
Следует отметить, что существуетcontext
Подобные функции также могут быть достигнуты, но это навязчивый способ написания, который официально не рекомендуется, поэтому в этой статье он не упоминается.
Этот процесс выглядит довольно просто, но для того, чтобы сделать это в Redux, нужно пройти более сложный процесс.
Давайте начнем путешествие Redux дальше.
3. Как использовать Редукс
Установить редукс:
$ npm install --save redux
or
$ yarn add redux
Сначала создайте src/Reducer.js
Store обычно используется в сочетании с Reducer, Store хранит данные, а Reducer — это чистая функция, которая получает и обновляет данные.
Сначала создайте Редьюсер.Для простоты запишите требуемое начальное значение непосредственно в состояние в редюсере.state = 0
Это данные инициализации для него (значение состояния может быть объектом, здесь число непосредственно), он также получает действие, когда тип действия «инкремент», он будет указывать + 1, иначе минус один.
Хотя здесь в редюсер записывается начальное значение, реальное хранилище — это хранилище, а роль редюсера — получать, обновлять и возвращать новые данные.
В то же время здесь видно, что то, как Reducer обновляет данные, зависит от значения типа входящего действия.
export default (state = 0, action) => {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
default:
return state;
}
};
Затем создайте src/Store.js
С помощью Reducer мы можем создать нужный нам магазин, этот магазин глобальный, и в него можно внедрить любой компонент реакции, который захочет его использовать.
import { createStore } from 'redux';
import Reducer from './Reducer';
const store = createStore(Reducer)
export default store;
Наконец, давайте изменим наш App.js
import React, { Component } from "react";
+ import store from "./Store";
export default class App extends Component {
+ onIncrement = () => {
+ store.dispatch({
+ type: "increment"
+ });
+ };
+ onDecrement = () => {
+ store.dispatch({
+ type: "decrement"
+ });
+ };
render() {
+ store.subscribe(() => console.log("Store is changed: " + store.getState()));
return (
<div className="container">
+ <h1 className="text-center mt-5">{store.getState()}</h1>
<p className="text-center">
<button className="btn btn-primary mr-2" onClick={this.onIncrement}>
Increase
</button>
<button className="btn btn-danger my-2" onClick={this.onDecrement}>
Decrease
</button>
</p>
</div>
);
}
}
store.getState()
Он используется для получения значения состояния в хранилище.store.subscribe()
Метод используется для прослушивания значения состояния в хранилище.Если состояние изменится, оно сработает, поэтому этот метод получает функцию. Метод subscribe() также может быть написан в componentDidMount().
Как я уже говорил, чтобы изменить значение состояния в хранилище, необходимо передать значение типа действия, Redux предусматривает, что значение этого действия должно быть отправлено методом диспетчеризации хранилища. .
так что используйтеstore.dispatch({type: 'increment'});
Этот простой способ записи позволяет легко передать нужное значение в редьюсер, а значение состояния можно изменить в это время.
Теперь вы можете проверить вышеуказанную операцию, вручную изменить значение состояния и обнаружить, что данные на странице также изменились, указывая на то, что данные на странице были успешно прочитаны из хранилища:
Щелкните после триггерного события, вы увидите, что успешное значение состояния изменилось, что указывает наstore.dispatch()
Тип этого действия для отправки — успешный.
Так почему же данные на странице не меняются? Это потому, что значение состояния было изменено, но страница не была перерисована. При использовании react для реализации этой функции вызывался метод setState() для изменить состояние.Этот метод также будет повторно отображать render().
Тогда вы действительно можете использовать этот метод setState() здесь.
Изменить App.js
import React, { Component } from "react";
import store from "./Store";
export default class App extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ count: store.getState()
+ };
+ }
onIncrement = () => {
...
};
onDecrement = () => {
...
};
render() {
+ store.subscribe(() =>
+ this.setState({
+ count: store.getState()
+ })
+ );
return (
...
);
}
}
Таким образом, с помощью метода setState реакции страница может быть перерисована одновременно с изменением значения в хранилище.
Простой пример редукса завершен здесь.
3.1. Действие извлечения
В приведенном выше примере метод store.dispatch () используется в функции, запускаемой событием onClick, для отправки типа Action, Фактически, это действие также может быть извлечено отдельно.
Новый источник/Action.js
export const increment = () => {
return {
type: "increment"
};
};
export const decrement = () => {
return {
type: "decrement"
};
};
Изменить App.js
import React, { Component } from "react";
import store from "./Store";
+import * as Action from './Action'
export default class App extends Component {
...
onIncrement = () => {
+ store.dispatch(Action.increment());
};
onDecrement = () => {
+ store.dispatch(Action.decrement());
};
render() {
...
}
}
Таким образом, контент в диспетчере извлекается отдельно, а контент в Action.js также представляет некоторые действия, выполняемые мышью пользователя.
Этот Action.js может быть дополнительно извлечен, поскольку значение типа является константой, поэтому его можно извлечь отдельно.
Новый ActionTypes.js
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
Затем вы можете изменить Actions.js
+import * as ActionTypes from './ActionType';
...
Тот же тип Reducer.js также можно изменить
+import * as ActionTypes from './ActionType';
export default (state = 0, action) => {
switch (action.type) {
+ case ActionTypes.INCREMENT:
return state + 1;
+ case ActionTypes.DECREMENT:
return state - 1;
default:
return state;
}
};
Здесь был реализован полный пример редукта, включая действие, редуктор, магазин, отправку, подписку и просмотр. Представление здесь относится к странице, предоставленной App.js, который является компонентом React.
А пока взгляните на карту заголовков, чтобы хорошо понять весь рабочий процесс Redux:
4. Как использовать реакцию-редукс
Использование избыточности в реакции на самом деле может быть немного более элегантным. редукс также предоставляетreact-redux
Плагин, следует отметить, что этот плагин играет только вспомогательную роль и не используется для замены редукса.
Что касается того, как использовать его, чтобы стать более элегантным, давайте начнем с кода:
Установите реакцию-редукс:
$ npm install --save react-redux
or
$ yarn add react-redux
Хранилище используется в каждом компоненте и должно быть введено отдельно согласно предыдущему методу.Здесь вы также можете использовать другой способ передать его непосредственно в компонент верхнего уровня, а затем получить его, когда компонент захочет его использовать. :
Измените index.js, который является компонентом верхнего уровня, импортируйте хранилище сюда и передайте его вниз
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
+import store from "./Store";
+import { Provider } from 'react-redux'
import registerServiceWorker from "./registerServiceWorker";
ReactDOM.render(
+ <Provider store={store}>
<App />
+ </Provider>,
document.getElementById("root")
);
registerServiceWorker();
Измените App.js и импортируйте его сюдаconnect
чтобы получить магазин, то вы можете использоватьthis.props
Чтобы использовать диспетчеризацию, состояние можно использовать с функцией для его получения.
import React, { Component } from "react";
import * as Action from "./Action";
+import { connect } from "react-redux";
-import store from "./Store";
+class App extends Component {
- constructor(props) {
- super(props);
- this.state = {
- count: store.getState()
- };
- }
onIncrement = () => {
+ this.props.dispatch(Action.increment());
};
onDecrement = () => {
+ this.props.dispatch(Action.decrement());
};
render() {
- store.subscribe(() =>
- this.setState({
- count: store.getState()
- })
- );
return (
<div className="container">
+ <h1 className="text-center mt-5">{this.props.count}</h1>
<p className="text-center">
<button className="btn btn-primary mr-2" onClick={this.onIncrement}>
Increase
</button>
<button className="btn btn-danger my-2" onClick={this.onDecrement}>
Decrease
</button>
</p>
</div>
);
}
}
+const mapStateToProps = state => ({
+ count: state
+});
+export default connect(mapStateToProps)(App);
Вы будете удивлены, обнаружив, что вам не нужно использоватьsetState
способ повторного рендеринга страницы, redux уже сделал это за нас. ты можешьconnect()()
Есть сомнения по поводу такого способа написания, это каррирующая функция, как реализован нижний слой в этой статье не обсуждается, теперь нужно только знать какие параметры передавать и как это использовать.
4.1. Действия по обработке
на самом деле используетсяreact-redux
После этого нам не только не нужно заботиться о том, как повторно отобразить страницу, но и не нужно вручную отправлять действия непосредственно вconnect
Действие передается в метод, а затем вызывается напрямую.
Снова измените App.js на основе вышеизложенного:
import React, { Component } from "react";
import * as Action from "./Action";
import { connect } from "react-redux";
class App extends Component {
- onIncrement = () => {
- this.props.dispatch(Action.increment());
- };
- onDecrement = () => {
- this.props.dispatch(Action.decrement());
- };
render() {
+ const { increment, decrement } = this.props;
return (
<div className="container">
<h1 className="text-center mt-5">{this.props.count}</h1>
<p className="text-center">
+ <button className="btn btn-primary mr-2" onClick={() => increment()}>
Increase
</button>
+ <button className="btn btn-danger my-2" onClick={() => decrement()}>
Decrease
</button>
</p>
</div>
);
}
}
const mapStateToProps = state => ({
count: state
});
+export default connect(mapStateToProps,Action)(App);
Здесь вы должны иметь возможность испытать использованиеreact-redux
Удобство плагина, на самом деле у него много других достоинств, и я не буду здесь приводить примеры.
5. Как использовать несколько редукторов
В Redux есть только одно глобальное хранилище. Если вам нужно управлять другими состояниями, вам может понадобиться использовать несколько редюсеров. Redux предоставляет одинcombineReducers
Можно соединить несколько редукторов вместе.
Вот еще демонстрацияcombineReducers
Для того, чтобы как можно меньше модифицировать файлы, я не стал создавать папку для управления классификацией, а файлы с разными функциями в процессе фактического использования должны располагаться в разных папках.
Создайте файл src/Reducer2.js
export default (state = "hello", action) => {
switch (action.type) {
default:
return state;
}
};
Создайте src/CombineReducer.js
import { combineReducers } from 'redux';
import count from './Reducer';
import hello from './Reducer2';
const rootReducer = combineReducers({
count,
hello
})
export default rootReducer;
Изменить Store.js
import { createStore } from 'redux';
+import rootReducer from './CombineReducer';
+const store = createStore(rootReducer)
export default store;
Изменить App.js
...
return (
<div className="container">
+ <h1 className="text-center mt-5">{this.props.text}{this.props.count}</h1>
...
</div>
);
}
}
const mapStateToProps = state => ({
count: state.count,
+ text: state.hello
});
...
Эффект следующий, вы можете прочитать соответствующее значение в магазине:
Наконец, полный код здесь:Github.com/ А так/React-...