1.redux是什么 ??
🌸 redux是一个专门用于状态管理的JS库
1.作用范围:它可以用在react,angular,Vue等项目中,但基本与react配合使用,(Vue一般使用Vuex)
2.作用:集中式管理react应用中多个组件的共享状态
2.什么时候用redux 🌀
1.某个组件的状态,需要让其他组件可以随时拿到(共享)
2.一个组件需要改变另一个组件的状态 (通信)
3.总体原则:能不用就不用,如果不用比较吃力才考虑使用
4.一般使用消息订阅与发布机制
3.redux的基本原则 ??
🌼 唯一数据源 🌼 保持状态只读 🌼 数据改变只能通过纯函数完成
1.唯一数据源指的是应用的状态数据,应该只存储在唯一的一个store上
2.保持状态只读,就是说不能去直接修改状态,要修改store的状态,必须要通过派发一个action对象完成。
(驱动用户界面渲染,就要改变应用的状态,但是改变状态的方法不是去修改状态上的值,而是创建一个新的状态对象返回给Redux,由Redux完成新的状态组装)
3.这里说的纯函数就是Reducer
在Redux中,reducer的函数签名: 🌐 reducer(state,action)
第一个参数state是当前的状态
第二个参数action是接受到的action对象,
而reducer函数要做的就是根据state和action的值产生一个新对象返回
注意reducer必须是一个纯函数,也就是说函数的返回结果必须完全由参数state和action决定,同时也不能修改参数state和action对象
4.redux的三个核心概念 ??
🌌 action
1.动作的对象
2.包含2个属性
type:标识属性,值为字符串,唯一,必要属性
data:数据属性,值类型任意,可选属性
3.例如: {type:"increment",data:10}
🌌 reducer
1.用于初始化状态,加工状态
2.加工时,根据旧的state和action,产生新的state的纯函数
🌌 store
1.将state,action,redux联系在一起
2.如何得到此对象?
①import {createStore} from 'redux'
②import reducer from './reducer'
③const store = createStore(reducer)
3.此对象的功能?
①getState():得到state
②dispatch(action):分发action,触发render调用,产生新的state
③subscribe(listener):注册监听,当产生了新的state时,自动调用
5.redux的核心API 🎯
🎬 createStore()
1.作用:创建包含指定reducer的store对象
🎬 store对象
1.作用:redux库最核心的管理对象
2.内部维护着:
state
reducer
3.核心方法:
①getState()
②dispatch(action)
③store.subscribe(listener)
4.具体实现
store.getState()
store.dispatch({type:'increment',data:100})
store.subscibe(render)
🎬 action
1.action有两种值:
object类型的action -----被称为同步类型的action
function类型的action -----被称为异步类型的action
2.异步action:延迟的动作不想交给组件自身,想交给action,想要对状态进行操作,但是具体的数据靠异步返回
3.怎样使用:yarn add redux-thunk ,并配置在store中,创建action函数不在返回一般对象,而是一个函数,该函数中写异步任务,异步任务有结果后,分发一个同步action去真正操作数据
案例: Count组件,在components/Count下
import React,{Component} from 'react'
import {Decrement,Increment} from '../../redux/count_action';
import store from '../../redux/store'
export default class Count extends Component{
increment=()=>{
const {value} = this.number;
store.dispatch(Increment(value*1));
}
decrement=()=>{
const {value} = this.number;
store.dispatch(Decrement(value*1));
}
IfOddIncrement= ()=>{
const {value} = this.number;
if(store.getState() % 2 !==0 ){
store.dispatch(Increment(value*1));
}
}
IncrementAsync=()=>{
const {value} = this.number;
setTimeout(()=>{
store.dispatch(Increment(value*1));
},1000)
}
render(){
return(
<div >
<h2 >当前的求和的值:{store.getState()}</h2>
<select ref={ c=> this.number=c } >
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.IfOddIncrement}>值为奇数时加</button>
<button onClick={this.IncrementAsync}>异步加</button>
</div>
)
}
}
redux文件夹下的: ?? action.js
const Increment = (data)=>{
return {type:'increment',
data:data
}
}
const Decrement = (data)=>{
return {
type:'decrement',
data,
}
}
export {Decrement,Increment};
?? reducer
const initState =10;
function reducer(preState=initState,action){
const {type,data} = action;
switch(type){
case 'increment':
return preState + data
case 'decrement':
return preState - data
default:
return preState;
}
}
export default reducer;
?? store
import {createStore} from 'redux'
import reducer from './count_reducer'
const store = createStore(reducer);
console.log(store);
export default store;
action和reducer可以有多个,但是store只能有一个
6.redux原理图 🔓
7.容器组件和UI组件(傻瓜组件) 🏄
React组件和Redux中store打交道,需要读取store的状态,用于初始化组件的状态,
同时还要监听store状态的改变,当store状态发生改变时,需要更新组件状态,从而驱动组件重新渲染。
一个组件做事情太多,后来就把一个组件拆分成两个组件,让每一个组件只专注做一件事。组件分为容器组件和傻瓜组件,拆分容器组件和傻瓜组件,是设计React组件的一种模式
💖 容器组件:外层组件,是UI组件的父组件 💞 UI组件:让UI组件无状态,UI组件只需要根据props来渲染结果, 👊 使用时,需要引入react-redux库,来连接容器组件和UI组件
案例
🍏 容器组件
import CountUI from '../../components/Count/index'
import {createIncrementAction,createDecrementAction,createIncrementActionAsync} from '../../redux/count_action'
import { connect } from 'react-redux'
function mapStateToProps(state){
return {
count:state
}
};
function mapDispatchToProps(dispatch){
return{
increment:(number)=>{
dispatch(createIncrementAction(number));
},
decrement:(number)=>{
dispatch(createDecrementAction(number));
},
incrementAsync:(number,timer)=>{
dispatch(createIncrementActionAsync(number,timer));
}
}
};
const Connect = connect(mapStateToProps,mapDispatchToProps)(CountUI);
export default Connect;
🍏 容器组件简写
import CountUI from '../../components/Count/index'
import {createIncrementAction,createDecrementAction,createIncrementActionAsync} from '../../redux/count_action'
import { connect } from 'react-redux'
const mapStateToProps = state=>({count:state});
const mapDispatchToProps=dispatch=>
({
increment:(number)=>{
dispatch(createIncrementAction(number));
},
decrement:(number)=>{
dispatch(createDecrementAction(number));
},
incrementAsync:(number,timer)=>{
dispatch(createIncrementActionAsync(number,timer));
}
});
export default connect(mapStateToProps,mapDispatchToProps)(CountUI);
🍎最终写法1:
import CountUI from '../../components/Count/index'
import {createIncrementAction,createDecrementAction,createIncrementActionAsync} from '../../redux/count_action'
import { connect } from 'react-redux'
export default connect(
state=>({count:state}),
dispatch =>
({
increment:(number)=>{
dispatch(createIncrementAction(number));
},
decrement:(number)=>{
dispatch(createDecrementAction(number));
},
incrementAsync:(number,timer)=>{
dispatch(createIncrementActionAsync(number,timer));
}
}))(CountUI);
mapDispatchToProps可以是
1.function
2.对象
🍎最终写法2
import CountUI from '../../components/Count/index'
import {createIncrementAction,createDecrementAction,createIncrementActionAsync} from '../../redux/count_action'
import { connect } from 'react-redux'
export default connect(
state=>({count:state}),
{
increment:createIncrementAction,
decrement:createDecrementAction,
incrementAsync:createIncrementActionAsync
}
)(CountUI);
🎡UI组件
import React,{Component} from 'react'
export default class CountUI extends Component{
increment=()=>{
const {value} = this.number;
this.props.increment(value*1);
};
decrement=()=>{
const {value} = this.number;
this.props.decrement(value*1);
};
incrementIfOdd=()=>{
const {value} = this.number;
const {count} = this.props;
if(count % 2 !==0){
this.props.increment(value*1);
}
};
incrementAsync=()=>{
const {value} = this.number;
this.props.incrementAsync(value*1,1000);
};
render(){
console.log(this);
return(
<div>
<h2>当前求和的值为:{this.props.count}</h2>
<select ref={c=>this.number=c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>为奇数时加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
)
}
}
🍬App的组件:(需要传递store,但是可以使用provider)
import React, {Component} from 'react';
import Count from './containers/Count/index'
export default class App extends Component{
render(){
return(
<Count/>
)
}
}
🍯 index入口函数 使用react-redux中提供的Provider,可以给所有容器组件传递一个store对象
import ReactDOM from 'react-dom';
import App from './App'
import {Provider} from 'react-redux';
import store from './redux/store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'));
🍉action
import store from './store'
const createIncrementAction = (data)=>{
return {
type:'increment',
data:data
}
}
const createDecrementAction = data=>({type:'decrement',data})
const createIncrementActionAsync = (data,time)=>{
return ()=>{
setTimeout(()=>{
store.dispatch(createIncrementAction(data));
},time)
}
}
export {createIncrementAction,createDecrementAction,createIncrementActionAsync};
🍓reducer
const initState = 100;
function reducer(preState=initState,action){
const {type,data} = action;
switch(type){
case 'increment':
return preState + data;
case 'decrement':
return preState - data;
default:
return preState;
}
}
export default reducer;
🍌store
import {createStore,applyMiddleware} from 'redux'
import reducer from './count_reducer'
import thunk from 'redux-thunk'
const store = createStore(reducer,applyMiddleware(thunk));
export default store;
8.合并容器组件和UI组件 🌈
import {createIncrementAction,createDecrementAction,createIncrementActionAsync} from '../../redux/count_action'
import { connect } from 'react-redux'
import React,{Component} from 'react'
class CountUI extends Component{
increment=()=>{
const {value} = this.number;
this.props.increment(value*1);
};
decrement=()=>{
const {value} = this.number;
this.props.decrement(value*1);
};
incrementIfOdd=()=>{
const {value} = this.number;
const {count} = this.props;
if(count % 2 !==0){
this.props.increment(value*1);
}
};
incrementAsync=()=>{
const {value} = this.number;
this.props.incrementAsync(value*1,1000);
};
render(){
console.log(this);
return(
<div>
<h2>当前求和的值为:{this.props.count}</h2>
<select ref={c=>this.number=c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>为奇数时加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
)
}
}
export default connect(
state=>({count:state}),
{
increment:createIncrementAction,
decrement:createDecrementAction,
incrementAsync:createIncrementActionAsync
}
)(CountUI);
|