1.redux是什么?
- redux是一个专门用于状态管理的JS库(不是react插件库)
- 它可以在react,angular,vue等项目中,但基本与react配合使用
- 作用:集中式管理react应用中多个组件共享状态
2.什么情况下需要使用redux
- 某个组件的状态,需要让其他组件可以随时拿到(共享)
- 一个组件需要改变另一个组件的状态(通信)
- 总体原则:能不用就不用,如果不用比较吃力才考虑使用
3.redux的工作流程
4.redux的三个核心概念
4.1action
- 动作的对象
- 包含两个属性
- type:标识属性,值为字符串,唯一,必要属性
- data:数据属性,值为任意类型,可选属性
- 例如:{type:‘ADD_STUDENT’,data:{name:‘tom’,age:18} }
4.2reducer
- 用于初始化状态,加工状态
- 加工时,根据旧的state和acticon,产生新的state的纯函数
4.3store
- 将state,action,reducer联系在一起的对象
- 如何得到此对象
- import {createStore} from ‘redux’
- import reducer from ‘./reducers’
- const store=createStore(reduce)
- 此对象的功能
- getState():得到state
- dispatch(action):分发action,触发reducer调用,产生新的state
- subscribe(listener):注册监听,当产生了新的state时,自动调用
5.案例-非redux版本
import React, {
Component } from 'react'
import ReactDOM from 'react-dom';
import {
BrowserRouter, NavLink, Route, Switch, Redirect, withRouter } from 'react-router-dom';
class App extends React.Component {
state = {
msg: '这里是App组件',
count: 0
}
increase = () => {
let {
value } = this.selectDOM;
let {
count } = this.state;
count += Number(value);
this.setState({
count
})
}
decrease = () => {
let {
value } = this.selectDOM;
let {
count } = this.state;
count -= Number(value);
this.setState({
count
})
}
oddIncrease = () => {
let {
value } = this.selectDOM;
let {
count } = this.state;
if (count % 2 == 0) {
count += Number(value);
this.setState({
count
})
}
}
asyncIncrease = () => {
let {
value } = this.selectDOM;
let {
count } = this.state;
setTimeout(() => {
count += Number(value);
this.setState({
count
})
}, 1000);
}
render() {
return (
<div className="app">
<h1>当前求和为{
this.state.count}</h1>
<select ref={
(currentNode) => {
this.selectDOM = currentNode;
}}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={
this.increase}>+</button>
<button onClick={
this.decrease}>-</button>
<button onClick={
this.oddIncrease}>求和为奇数加</button>
<button onClick={
this.asyncIncrease}>异步+</button>
</div>
)
}
}
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>, document.querySelector('#root'));
6.redux-精简版
- 笔记
- 去除组件自身需要让redux管理的状态
- .src下建立
- store.js
- 引入redux中createStore函数,创建一个store
- createStore调用时要传入一个为其服务的reducer
- 暴露store对象
- reducer.js
- reducer本质是一个函数,接受prevState,action,返回加工后的状态
- reducer有两个作用:初始化状态/加工状态
- reducer第一次被调用的时候,是store自动触发的,传递prevState是undefined/传递的action:{type:@@redux/INITw.a.v.g.2.j}
- 在index.js中检测store中状态的改变,一旦发生改变就重新渲染组件
- redux值负责管理状态,至于状态的改变驱动着页面的展示,就需要自己完成了
- reducer.js
let initState = 0;
function storeReducer(prevState = initState, action) {
let {
type, data } = action;
switch (type) {
case 'increase':
return prevState += data;
case 'decrease':
return prevState -= data;
default:
return prevState
}
}
export default storeReducer;
import {
createStore } from 'redux';
import storeReducer from './reducer';
let store = createStore(storeReducer);
export default store;
import React from 'react';
import './index.scss';
import store from './redux/store.js';
class App extends React.Component {
state = {
msg: '这里是App组件',
count: 996
}
increase = () => {
let {
value } = this.selectDOM;
store.dispatch({
type: 'increase',
data: Number(value)
})
}
decrease = () => {
let {
value } = this.selectDOM;
store.dispatch({
type: 'decrease',
data: Number(value)
})
}
oddIncrease = () => {
let count = store.getState();
if (count % 2 == 0) {
this.increase();
}
}
asyncIncrease = () => {
setTimeout(() => {
this.increase();
}, 1000);
}
render() {
return (
<div className="app">
<h1>当前求和为{
store.getState()}</h1>
<select ref={
(currentNode) => {
this.selectDOM = currentNode;
}}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={
this.increase}>+</button>
<button onClick={
this.decrease}>-</button>
<button onClick={
this.oddIncrease}>求和为偶数加</button>
<button onClick={
this.asyncIncrease}>异步+</button>
</div>
)
}
}
export default App;
import React from 'react'
import ReactDOM from 'react-dom';
import {
BrowserRouter } from 'react-router-dom';
import App from './App.jsx'
import './normalize.css';
import store from './redux/store.js';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>, document.querySelector('#root'));
store.subscribe(() => {
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>, document.querySelector('#root'));
})
7.redux-完整版
- 新增文件
- action.js 专门用于创建action对象
- constant.js 防止容易写错的type值
- constant.js
export const INCREASE = 'increase';
export const DECREASE = 'decrease';
import {
INCREASE, DECREASE } from './constant.js';
export function createIncrease(data) {
return {
type: INCREASE, data: data }
}
export function createDecrease(data) {
return {
type: DECREASE, data: data }
}
import {
INCREASE, DECREASE } from './constant.js';
let initState = 0;
function storeReducer(prevState = initState, action) {
let {
type, data } = action;
switch (type) {
case INCREASE:
return prevState += data;
case DECREASE:
return prevState -= data;
default:
return prevState
}
}
export default storeReducer;
import {
createStore } from 'redux';
import storeReducer from './reducer';
let store = createStore(storeReducer);
export default store;
import React from 'react';
import './index.scss';
import store from './redux/store.js';
import {
createIncrease, createDecrease } from './redux/action.js';
class App extends React.Component {
state = {
msg: '这里是App组件'
}
increase = () => {
let {
value } = this.selectDOM;
store.dispatch(createIncrease(Number(value)))
}
decrease = () => {
let {
value } = this.selectDOM;
store.dispatch(createDecrease(Number(value)))
}
oddIncrease = () => {
let count = store.getState();
if (count % 2 !== 0) {
this.increase();
}
}
asyncIncrease = () => {
setTimeout(() => {
this.increase();
}, 1000);
}
render() {
return (
<div className="app">
<h1>当前求和为{
store.getState()}</h1>
<select ref={
(currentNode) => {
this.selectDOM = currentNode;
}}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={
this.increase}>+</button>
<button onClick={
this.decrease}>-</button>
<button onClick={
this.oddIncrease}>求和为奇数加</button>
<button onClick={
this.asyncIncrease}>异步+</button>
</div>
)
}
}
export default App;
import React from 'react'
import ReactDOM from 'react-dom';
import {
BrowserRouter } from 'react-router-dom';
import App from './App.jsx'
import './normalize.css';
import store from './redux/store.js';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>, document.querySelector('#root'));
store.subscribe(() => {
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>, document.querySelector('#root'));
})
8.redux-异步版
- 明确:延yi便迟的动作不想交给组件自身,想交给action
- 何时需要action:想要对状态进行操作,但是具体的数据靠异步任务返回
- 具体编码
- cnpm install redux-thunk ,并配置在store中
- 创建action的函数不再返回一般对象 ,而是一个函数,该函数中写异步任务
- 异步任务又结果之后,分发给一个同步的action去真正操作数据
- 备注:异步action不是必须要写的,完全可以自己等待异步任务的结果再去分发同步action
- constant.js
export const INCREASE = 'increase';
export const DECREASE = 'decrease';
import {
INCREASE, DECREASE } from './constant.js';
export function createIncrease(data) {
return {
type: INCREASE, data: data }
}
export function createDecrease(data) {
return {
type: DECREASE, data: data }
}
export function createIncreaseAsyncAction(data, speed) {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrease(data))
}, speed);
}
}
import {
INCREASE, DECREASE } from './constant.js';
let initState = 0;
function storeReducer(prevState = initState, action) {
let {
type, data } = action;
switch (type) {
case INCREASE:
return prevState += data;
case DECREASE:
return prevState -= data;
default:
return prevState
}
}
export default storeReducer;
import {
createStore, applyMiddleware } from 'redux';
import storeReducer from './reducer';
import thunk from 'redux-thunk';
let store = createStore(storeReducer, applyMiddleware(thunk));
export default store;
import React from 'react';
import './index.scss';
import store from './redux/store.js';
import {
createIncrease, createDecrease, createIncreaseAsyncAction } from './redux/action.js';
class App extends React.Component {
state = {
msg: '这里是App组件'
}
increase = () => {
let {
value } = this.selectDOM;
store.dispatch(createIncrease(Number(value)))
}
decrease = () => {
let {
value } = this.selectDOM;
store.dispatch(createDecrease(Number(value)))
}
oddIncrease = () => {
let count = store.getState();
if (count % 2 !== 0) {
this.increase();
}
}
asyncIncrease = () => {
let {
value } = this.selectDOM;
store.dispatch(createIncreaseAsyncAction(Number(value), 1000))
}
render() {
return (
<div className="app">
<h1>当前求和为{
store.getState()}</h1>
<select ref={
(currentNode) => {
this.selectDOM = currentNode;
}}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={
this.increase}>+</button>
<button onClick={
this.decrease}>-</button>
<button onClick={
this.oddIncrease}>求和为奇数加</button>
<button onClick={
this.asyncIncrease}>异步+</button>
</div>
)
}
}
export default App;
import React from 'react'
import ReactDOM from 'react-dom';
import {
BrowserRouter } from 'react-router-dom';
import App from './App.jsx'
import './normalize.css';
import store from './redux/store.js';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>, document.querySelector('#root'));
store.subscribe(() => {
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>, document.querySelector('#root'));
})