跟着尚硅谷的天禹老师学习React
看视频可以直接点击 b站视频地址
简介
redux是什么
- redux是一个专门用于状态管理的JS库(不是react插件库)
- 它可以用在react,angular,vue等项目中,但基本与react配合使用。
- 作用:集中式管理react应用中多个组件共享的状态
redux在什么情况下使用
- 某个组件的状态,需要让其他组件可以随时拿到(共享)
- 一个组件需要改变另一个组建的状态(通信)
- 总体原则:能不用就不用,除非比较难以实现的时候再用。
redux的三个核心概念
- action
- 动作的对象
- 包含两个属性:
- type:标识属性,值为一个字符串,唯一,必填
- data:数据属性,值类型任意,可选
- 例子:{type:‘ADD_STUDENT’,data:{name:‘tom’,age:18}}
- reducer
- 用于初始化状态、加工状态
- 加工时,根据旧的state和action,产生新的state的纯函数
- store
- 将state、action、reducer联系在一起的对象
- 如何得到这个对象?
- import {createStore} from ‘redux’
- import reducer from ‘./reducers’
- const store = createStore(reducer)
- 此对象的功能?
- getState():得到state
- dispatch(action):分发action,触发reducer调用,产生新的state
- subscribe(listener):注册监听,当产生了新的state时,自动调用
redux的核心API
redux编写应用:加减计算器
目录结构
代码
Count.jsx
/* Count.jsx */
import React, { Component } from "react";
// 引入store,用于获取store的状态
import store from "../../redux/store";
export default class Count extends Component {
state = {
count: 0,
};
componentDidMount() {
store.subscribe(() => {
this.setState({});
});
}
increment = () => {
const { value } = this.selectNumber;
store.dispatch({ type: "increment", data: value * 1 });
};
decrement = () => {
const { value } = this.selectNumber;
store.dispatch({ type: "decrement", data: value * 1 });
};
incrementOdd = () => {
const { value } = this.selectNumber;
const count = store.getState();
const result = count + value * 1;
if (result % 2 !== 0) {
store.dispatch({ type: "increment", data: value * 1 });
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
setTimeout(() => {
store.dispatch({ type: "increment", data: value * 1 });
}, 500);
};
render() {
return (
<div>
<h1>当前求和为:{store.getState()}</h1>
<select ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<br></br>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementOdd}>求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
counter_reducer.js
/* counter_reducer.js */
/** 用于创建一个为Count组件服务的reducer
* reducer会接收两个参数一个是原状态,一个是动作对象
*/
const initState = 0;
export default function (preState = initState, action) {
console.log(preState,action)
// 从action对象中获取:type、data
const { type, data } = action;
// 根据type决定如何加工数据
switch (type) {
case "increment":
return preState + data;
case "decrement":
return preState - data;
default:
// 初始化
return preState;
}
}
store.js
/** 该文件专门用于暴露一个store对象 */
// 引入createStore
import { createStore } from "redux";
import countReducer from "./count_reducer";
export default createStore(countReducer);
一个小技巧
如果在componentDidMount生命周期钩子中监听store的变化,一旦这个状态用得很多,我们可以这样做:直接在index.js中监听这个状态的变化。因为有diffing的原因所以这个性能损耗不会太高。
store.subscribe(() => {
ReactDOM.render(<App />, document.getElementById("root"));
});
小结
- 使用createStore函数来创建一个store
- 注意创建createStore时要传入一个reducer
- reducer本质是一个纯函数,接收preState和action,返回加工后的状态。
- reducer有两个作用:初始化状态,加工状态
- reducer被第一调用时是store自动触发的,传递的preState是undefined,action是一个包含“@@redux/INITg.b.n.m.h.7”字符串的对象
- redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。
完整的redux使用
增加了constant和action两个部分,constant为了统一管理type字符串,action是为了创建action时更简洁。
constant.js
/* constant.js */
/**
* 该模块适用于定义action对象中type类型的常量值
* 单纯是为了防止常量改错,并且防止重新命名时难以维护
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
count_action.js
/* count_action.js */
/**
* 该文件专门为Count组件生成action对象
*/
import { DECREMENT, INCREMENT } from "./constant";
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
count_reducer.js
/* count_reducer.js */
/** 用于创建一个为Count组件服务的reducer
* reducer会接收两个参数一个是原状态,一个是动作对象
*/
import {INCREMENT,DECREMENT} from './constant'
const initState = 0;
export default function (preState = initState, action) {
// 从action对象中获取:type、data
const { type, data } = action;
// 根据type决定如何加工数据
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
// 初始化
return preState;
}
}
store.js
/* store.js */
/** 该文件专门用于暴露一个store对象 */
// 引入createStore
import { createStore } from "redux";
import countReducer from "./count_reducer";
export default createStore(countReducer);
异步action
action分为两种类型,一种是Object类型的,称为同步action;一种是function类型的,称为异步action。
redux-thunk中间件
由于store只期待接收一个一般的object,所以必须引入中间件来处理这个问题。
代码
修改后的store.js
/* 修改后的store.js */
/** 该文件专门用于暴露一个store对象 */
// 引入createStore
import { createStore,applyMiddleware } from "redux";
// 引入为store服务的reducer
import countReducer from "./count_reducer";
// 引入为redux-thunk,用于支持异步action、
import thunk from 'redux-thunk'
// 暴露store
export default createStore(countReducer,applyMiddleware(thunk));
修改后的count_action.js
/* 修改后的count_action.js */
/**
* 该文件专门为Count组件生成action对象
*/
import { DECREMENT, INCREMENT } from "./constant";
// 同步action就是指action的值为Object
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
// 异步action就是指action的值为函数,异步action一般都会调用同步action,异步action一般不是必须使用的
export const createIncrementAsyncAction = (data, delay) => {
return (dispatch) => { // store会传入一个dispatch参数
setTimeout(() => {
dispatch(createIncrementAction(data));
}, delay);
};
};
可以看到我们在createIncrementAsyncAction中声明了两个形式参数,所以在调用方法的时候应该这样传:
store.dispatch(createIncrementAsyncAction(value * 1,500));
小结
- 明确:延迟的动作不想交给组件本身,想要交给action
- 何使需要异步action:想要对状态进行操作,但是具体的数据要靠异步任务返回
- 具体编码
- npm install redux-thunk,并配置在store中
- 创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务
- 异步任务有结果后,分发一个同步的action去真正操作数据
- 备注:异步action不是必须要写的。完全可以自己等待异步任务的结果再去分发同步action
对react-redux的理解
redux本身是另一个团队的研发产品,因为很多react开发者都使用redux做状态管理,所以facebook也出了一个react-redux库。
- 所有的UI组件都应该包裹一个容器组件,它们是父子关系
- 容器组件是真正跟redux打交道的,里面可以随意地使用redux的api
- UI组件中不能使用任何redux的api
- 容器组件会传给UI组件:
- redux中所保存的状态
- 用于操作状态的方法
- 备注:容器给UI传递的状态和操作状态的方法,均通过props传递。
react似乎不希望开发者直接在UI组件中修改redux中的值。
使用react-redux完成计算器案例
目录
代码
App.js
/* App.js */
import React, { Component } from "react";
import Count from './containers/Count'
import store from "./redux/store";
export default class App extends Component {
render() {
return (
<div>
{/* 必须通过props的方式传入store */}
<Count store={store}/>
</div>
);
}
}
constant.js
/* constant.js */
/**
* 该模块适用于定义action对象中type类型的常量值
* 单纯是为了防止常量改错,并且防止重新命名时难以维护
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
count_action.js
/* count_action.js */
/**
* 该文件专门为Count组件生成action对象
*/
import { DECREMENT, INCREMENT } from "./constant";
// 同步action就是指action的值为Object
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
// 异步action就是指action的值为函数,异步action一般都会调用同步action,异步action一般不是必须使用的
export const createIncrementAsyncAction = (data, delay) => {
return (dispatch) => { // store会传入一个dispatch参数
setTimeout(() => {
dispatch(createIncrementAction(data));
}, delay);
};
};
count_reducer.js
/* count_reducer.js */
/** 用于创建一个为Count组件服务的reducer
* reducer会接收两个参数一个是原状态,一个是动作对象
*/
import {INCREMENT,DECREMENT} from './constant'
const initState = 0;
export default function (preState = initState, action) {
// 从action对象中获取:type、data
const { type, data } = action;
// 根据type决定如何加工数据
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
// 初始化
return preState;
}
}
store.js
/* store.js */
/** 该文件专门用于暴露一个store对象 */
// 引入createStore
import { createStore,applyMiddleware } from "redux";
// 引入为store服务的reducer
import countReducer from "./count_reducer";
// 引入为redux-thunk,用于支持异步action、
import thunk from 'redux-thunk'
// 暴露store
export default createStore(countReducer,applyMiddleware(thunk));
UI Count
/* UI Count */
import React, { Component } from "react";
export default class Count extends Component {
increment = () => {
const { value } = this.selectNumber;
this.props.jia(value * 1);
};
decrement = () => {
const { value } = this.selectNumber;
this.props.jian(value * 1);
};
incrementOdd = () => {
const { value } = this.selectNumber;
if (this.props.count % 2 !== 0) {
this.props.jia(value * 1);
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.jiaAsync(value*1,500)
};
render() {
// console.log(this.props);
return (
<div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<br></br>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementOdd}>求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
容器 Count
/* 容器Count */
// 引入Count的UI组件
import CountUI from "../../components/Count";
// 引connect用于连接UI组件与redux
import { connect } from "react-redux";
// 引入action
import { createIncrementAction ,createDecrementAction,createIncrementAsyncAction} from "../../redux/count_action";
/**
* 1. mapStateToProps函数的返回的是一个对象:
* 2. 对象的key作为传递给UI组件的props的key,value作为传递给UI组件的props的value
* 3. mapStateToProps用于传递状态
*/
const mapStateToProps = (state) => {
return {
count: state,
};
};
/**
* 1. mapStateToProps函数的返回的是一个对象:
* 2. 对象的key作为传递给UI组件的props的key,value作为传递给UI组件的props的value
* 3. mapStateToProps用于传递操作状态的方法
*/
const mapDispatchToProps = (dispatch) => {
return {
// 通知redux执行加法
jia: (number) => dispatch(createIncrementAction(number)),
jian: (number) => dispatch(createDecrementAction(number)),
jiaAsync: (number,delay) => dispatch(createIncrementAsyncAction(number,delay)),
};
};
// 使用connect创建并暴露一个Count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(CountUI);
react-redux的基本使用小结
- 明确两个概念:
- UI组件:不能使用任何redux的api,只负责页面的呈现和交互
- 容器组件:负责和redux通信,将结果交给UI组件
- 如何创建一个容器组件:使用react-redux的connect函数
- mapStateToprops:映射状态,返回值是一个对象
- mapDispatchToProps:映射操作状态的方法,返回值是一个对象
- 备注:容器组件中的store式靠props传进去的,而不是直接在容器组件中直接引入
优化1-MapDispatchToProps的简写
对于MapDispatchToProps直接传函数名即可。redux会自动分发这个action。
/* ( containers/Count.jsx ) */
// 引入Count的UI组件
import CountUI from "../../components/Count";
// 引connect用于连接UI组件与redux
import { connect } from "react-redux";
// 引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/count_action";
// 使用connect创建并暴露一个Count的容器组件
export default connect((state) => ({ count: state }), {
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
})(CountUI);
所以MapDispatchToProps可以传入两种类型的参数:
- 函数,有一个dispatch的参数,要手动分发。
- 对象,给出创建action的函数名,redux自动分发。
优化2-connect对于redux的优化
不需要手动监听状态变化然后再渲染组件,react-redux正在connect的时候已经做完这部分的工作。
优化3-Provider组件的使用
Provider组件和connect方法可以自动地分析react代码中需要传入store的组件,然后自动注入。
/* index.js */
// 引入React核心库
import React from "react";
// 引入ReactDOM
import ReactDOM from "react-dom";
// 引入App组件
import App from "./App";
import store from "./redux/store";
import { Provider } from "react-redux";
// 渲染App到页面
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
App.js
/* App.js */
import React, { Component } from "react";
import Count from './containers/Count'
export default class App extends Component {
render() {
return (
<div>
{/* 这里已经不需要通过Props传入store了 */}
<Count/>
</div>
);
}
}
优化4-整合容器组件和UI组件
既然只需要渲染一下那个容器组件即可,那么可以直接将UI组件和容器组件放在一个文件内。默认暴露容器组件,分别暴露UI组件。现在可以直接把components文件夹给删掉了。
import React, { Component } from "react"
// 引connect用于连接UI组件与redux
import { connect } from "react-redux";
// 引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/count_action";
// 定义UI组件
export class CountUI extends Component {
increment = () => {
const { value } = this.selectNumber;
this.props.jia(value * 1);
};
decrement = () => {
const { value } = this.selectNumber;
this.props.jian(value * 1);
};
incrementOdd = () => {
const { value } = this.selectNumber;
if (this.props.count % 2 !== 0) {
this.props.jia(value * 1);
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.jiaAsync(value*1,500)
};
render() {
// console.log(this.props);
return (
<div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<br></br>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementOdd}>求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
// 使用connect创建并暴露一个Count的容器组件
export default connect((state) => ({ count: state }), {
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
})(CountUI);
优化小结
- 容器组件和UI组件整合成一个文件
- 无需自己给容器组件传入store
- 使用了react-redux后也不用自己再检测redux中状态的改变,容器组件可以自动地完成这个工作
- mapDispatchToProps可以简单地写成一个对象
- 一个组件和redux”打交道“要经过哪几步?
- 定义好UI组件(不暴露)
- 引入connect生成一个容器组件,并暴露,写法如下:
connect(
state => ({key:value}), // 映射状态
{key:xxxxxAction} // 映射操作状态的方法
)(UI组件) - 在UI组件中通过this.props.xxxxxx读取和操作状态
实现数据共享
模拟了真实的开发场景,多个组件同时操作一个状态。
功能需求
目录
代码
index.js
注意这里使用Provider组件包裹了App,节省了手动注入state的操作。
// 引入React核心库
import React from "react";
// 引入ReactDOM
import ReactDOM from "react-dom";
// 引入App组件
import App from "./App";
import store from "./redux/store";
import { Provider } from "react-redux";
// 渲染App到页面
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
App.js
新增了一个Person组件
import React, { Component } from "react";
import Count from './containers/Count'
import Person from "./containers/Person";
export default class App extends Component {
render() {
return (
<div>
{/* 必须通过props的方式传入store */}
<Count/>
<hr />
<Person/>
</div>
);
}
}
store.js
这里使用thunk来完成异步action的操作,使用combineReducer完成reducers的合并(汇总)。并且可以在state中以count和persons为键保存这两个状态。
/** 该文件专门用于暴露一个store对象 */
// 引入createStore
import { createStore, applyMiddleware, combineReducers } from "redux";
// 引入为store服务的reducer
import countReducer from "./reducers/count";
// 引入为person服务的reducer
import personReducer from "./reducers/person";
// 引入为redux-thunk,用于支持异步action、
import thunk from "redux-thunk";
// 汇总所有reducer
const allReducer = combineReducers({
count: countReducer,
persons: personReducer,
});
// 暴露store
export default createStore(allReducer, applyMiddleware(thunk));
constant.js
暴露一些常量,防止程序员写错。
/**
* 该模块适用于定义action对象中type类型的常量值
* 单纯是为了防止常量改错,并且防止重新命名时难以维护
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = "add_person"
actions/count.js
向Count组件提供生成action的方法
/**
* 该文件专门为Count组件生成action对象
*/
import { DECREMENT, INCREMENT } from "../constant";
// 同步action就是指action的值为Object
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
// 异步action就是指action的值为函数,异步action一般都会调用同步action,异步action一般不是必须使用的
export const createIncrementAsyncAction = (data, delay) => {
return (dispatch) => { // store会传入一个dispatch参数
setTimeout(() => {
dispatch(createIncrementAction(data));
}, delay);
};
};
actions/person.js
import { ADD_PERSON } from "../constant";
// 创建增加一个人的action
export const createAddPersonAction = (person) => ({
type: ADD_PERSON,
data: person,
});
reducers/count.js
/** 用于创建一个为Count组件服务的reducer
* reducer会接收两个参数一个是原状态,一个是动作对象
*/
import {INCREMENT,DECREMENT} from '../constant'
const initState = 0;
export default function (preState = initState, action) {
// 从action对象中获取:type、data
const { type, data } = action;
// 根据type决定如何加工数据
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
// 初始化
return preState;
}
}
reducers/person.js
import { ADD_PERSON } from "../constant";
// 初始化人的列表
const initState = [{ name: "tom", id: "001", age: 18 }];
export default function personReducer(preState = initState, action) {
const { type, data } = action;
switch (type) {
case ADD_PERSON:
return [data, ...preState];
default:
return preState;
}
}
Count.jsx
Count的UI组件和容器组件,注意这里的“jia”、“jian”就是传给UI组件的操作状态的方法。count和persons就是传入组件的状态。
import React, { Component } from "react";
// 引connect用于连接UI组件与redux
import { connect } from "react-redux";
// 引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/actions/count";
// 定义UI组件
export class CountUI extends Component {
increment = () => {
const { value } = this.selectNumber;
this.props.jia(value * 1);
};
decrement = () => {
const { value } = this.selectNumber;
this.props.jian(value * 1);
};
incrementOdd = () => {
const { value } = this.selectNumber;
if (this.props.count % 2 !== 0) {
this.props.jia(value * 1);
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.jiaAsync(value * 1, 500);
};
render() {
return (
<div>
<h1>我是Count组件</h1>
<h1>当前求和为:{this.props.count}</h1>
<select ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<br></br>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementOdd}>求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
<h2>下方人数和为:{this.props.persons.length}</h2>
</div>
);
}
}
// 使用connect创建并暴露一个Count的容器组件
export default connect(
(state) => ({ count: state.count, persons: state.persons }),
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
}
)(CountUI);
Person.jsx
Person的UI组件和容器组件,注意这里将persons和count包裹成了一个名为state的prop传入了组件。
import React, { Component } from "react";
import { nanoid } from "nanoid";
import { connect } from "react-redux";
import { createAddPersonAction } from "../../redux/actions/person";
export class PersonUI extends Component {
addPerson = () => {
const name = this.nameNode.value;
const age = this.ageNode.value;
const id = nanoid();
const person = { name, age, id };
this.props.addPerson(person)
};
render() {
console.log(this.props)
return (
<div>
<h1>我是Person组件</h1>
<input
ref={(c) => (this.nameNode = c)}
type="text"
placeholder="输入名字"
></input>
<input
ref={(c) => (this.ageNode = c)}
type="text"
placeholder="输入年龄"
></input>
<button onClick={this.addPerson}>添加</button>
<ul>
{this.props.state.persons.map((person) => {
return (
<li key={person.id}>
姓名:{person.name}---年龄:{person.age}
</li>
);
})}
</ul>
<h2>上方求和为{this.props.state.count}</h2>
</div>
);
}
}
export default connect((state) => ({ state:state }), {
addPerson: createAddPersonAction,
})(PersonUI);
小结
- Person的reducer和Count的reducer要使用combineReducers进行合并,合并后的总状态是一个对象。
- 交给store的总是reducer,最后注意在组件中取出状态的时候,记得要“取到位”。
小的修改
1、在reducers文件夹下新建index.js文件汇总所有的reducers
/* reducers/index.js */
import count from './count'
import person from './person'
import { combineReducers } from 'redux'
const allReducer = combineReducers({count,person})
export default allReducer
2、将actions中的文件,将createXxxxxx都变成简单的意思,比如createIncrementAction改成increment,这样会减少代码量。
actions/count.js
/* actions/count.js */
/**
* 该文件专门为Count组件生成action对象
*/
import { DECREMENT, INCREMENT } from "../constant";
// 同步action就是指action的值为Object
export const increment = (data) => ({ type: INCREMENT, data });
export const decrement = (data) => ({ type: DECREMENT, data });
// 异步action就是指action的值为函数,异步action一般都会调用同步action,异步action一般不是必须使用的
export const createIncrementAsyncAction = (data, delay) => {
return (dispatch) => { // store会传入一个dispatch参数
setTimeout(() => {
dispatch(increment(data));
}, delay);
};
};
Count.jsx
/* Count.jsx */
export default connect(
(state) => ({ count: state.count, persons: state.persons }),
{
increment,
decrement,
incrementAsync,
}
)(CountUI);
纯函数
在写上一个案例时,reducers/person.js中要写成一个返回新数组的返回值。
return [data, ...preState];
如果我们使用preState.unshift(data),发现状态的改变并不能被检测到,这是因为react-redux仅对数据进行了一个“浅比较”,发现数组的引用地址并没有变,被认为没有进行数据的更新。所以必须使用纯函数的思想来处理。
因此redux规定:reducer必须为一个纯函数。
纯函数(Prue function)具有以下特点:
- 纯函数每一次调用时传入同样的参数,返回的都是同样的结果;它不会改变参数的值,也不会改变外部变量的值;它不会依赖于外部的变量,仅依赖于你传入的参数;
- 纯函数没有其他副作用(side effect),例如不能有I/O操作、网络请求。
- 如果你每次传入的参数一样,但是返回的结果不一样,则不是一个纯函数(也就是说只要输入相同,那输出一定也相同)
纯函数更像是数学中的函数。纯函数是函数式编程的基础。
redux开发者工具
1、首先需要在chrome插件市场下载redux-devtools,如果没有外网条件可以去一些类似极简插件的网站下载,使用开发者模式安装。
2、安装一个名为redux-devtools-extension的库
npm install redux-devtools-extension
3、在redux/store.js中引入composeWithDevTools
然后在createStore的第二个参数里再套一层
import { composeWithDevTools } from "redux-devtools-extension";
export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)) );
4、检查一下chrome开发者工具里是否有redux那个标签,如果有并且能够使用就是安装成功了。
打包项目
1、npm run build 或 yarn build,当然这都是根据package.json中scripts的值来决定的。
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
2、打包完成后会有一个build文件夹,这个就是最终产物。
部署项目
1、我们可以借用一个简单的库:serve,来简单部署一下这个打包后的文件。使用npm【全局安装】serve库
npm install serve -g
2、进入build目录下,输入serve指令。入过不希望进入在build目录,可以在项目根目录下 serve build。