目录
一、Redux
Redux:是一个状态管理的库。不是React内置的,是独立的JavaScript的状态容器,提供可预测的状态管理。在React中使用Redux,可以把所有的state集中到组件的顶部,能够灵活地将所有的state分发给所有的组件。方便了开发者管理React中的状态,也方便了不同组件间的通信
1、三大核心
store
:是一个数据容器,用来管理和保存整个项目的state。整个项目中只能有一个storestate
:是一个对象,在state中存储相应的数据,当开发者需要使用数据时,可以通过store提供的方法来获取stateaction
:是一个通知命令,用于对state进行修改。通过store提供的方法可以发起一个动作(action)完成对state的修改
2、Redux的函数
(1)action:本质是JavaScript对象,在action中包含一个字符串类型的type属性,作用是指定要对state进行何种操作。
action会通过store将要进行的操作传给reducer函数,由reducer完成对state的修改
action({type:'add',data:''})
(2)reducer:是一个纯函数。有两个参数state和action。该函数一定有一个返回值,是修改后的state。
纯函数:
a、纯函数在执行过程中没有任何的副作用。如定时器、网络请求。
b、如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部状态或数据的变化。
function reducer(state = { count:1},action) {
switch(action.type){
case 'ADD':
return { count:state.count+1 }
case 'SUB':
return { count:state.count-1 }
}
return state;
}
(3)createStore:用于创建store,参数必须是reducer,reducer函数名可以自定义
3、store对象提供的方法
(1)getState:用来获取state
(2)dispatch(action):派发动作(action)给reducer
(3)subscribe(listener):会注册一个监听器来监听state的变化。会返回一个注销监听器的方法 。 Redux的工作模式:发布-订阅模式
举例:利用Redux实现计数器
💥举例:利用Redux实现计数器
index.js(自定义的js文件): 创建纯函数和一个状态容器
//版本问题createStore已修改为legacy_createStore,但可以通过以下形式修改成简单写法
import {legacy_createStore as createStore} from "redux";
//创建一个纯函数:
function reducer(state={count:1},action){
console.log('Action'+action.type);
switch (action.type){
case 'ADD':
return{count:state.count+1};
case 'SUB':
return{count:state.count-1}
default:
return state;
}
}
//2.创建状态的容器:store
let store = createStore(reducer);
//3.导出store
export default store;
}
Counter.jsx代码段:
import React from "react";
//导入数据的状态容器store
import store from "../store";
class Counter extends React.Component{
constructor(props) {
super(props);
this.state = { //定义组件自己的状态
number:store.getState().count //将容器中的state的count值赋给自己的状态属性
}
}
//组件挂载之前进行订阅
componentDidMount() {
this.unSubScribe = store.subscribe(()=>{
this.setState({
number:store.getState().count
})
})
}
//组件卸载时取消订阅
componentWillUnmount() {
this.unSubScribe && this.unSubScribe() //如果订阅了store,就取消订阅
}
render(){
return(
<>
<p>{ this.state.number}</p>
<button onClick={()=>{ store.dispatch({type:'ADD'})}}>加1</button>
<button onClick={()=>{ store.dispatch({type:'SUB'})}}>减1</button>
</>
)
}
}
export default Counter;
App.js:
import logo from './logo.svg';
import './App.css';
import Counter from "./components/Counter";
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
</header>
<Counter/>
</div>
);
}
export default App;
4、在组件(类组件)中使用redux的过程
(1)安装:npm install redux
(2)通过store的getState()方法获取store中状态属性的值
(3)通过store的dispatch方法向纯函数派送动作
(4)通过store的subscribe方法对store进行订阅
具体使用方法参考上一个示例
5、Redux使用的缺点
每个组件在使用时都要引入store,当组件嵌套时,整个操作会非常麻烦
二、React-Recux
1、特点
(1)是React官方的绑定库
(2)可以实现所有组件共享store
(3)虽然是React官方的绑定库,但使用时仍然需要安装(npm i react-redux),通常要和redux结合使用。
2、组成部分
(1)Provider组件:作用是将store共享给包含在<Provider>
中的所有子组件
<Provider store={ 用户定义的store} > // store是Provider组件的属性
<App/>
</Provider>
含义:将用户定义的’store’共享给App的所有子组件
(2)connect组件/函数:是一个React定义的高阶组件。所谓的高阶组件就是给它传入一个组件,它会返回新的加工后的组件
connect(state=>newProps)(Component)
connect函数的参数:
mapStateToProps
:本质是一个函数,用来监听store的state的变化,一旦发现state发生了改变,该函数就就会自动执行。
mapDispatchToProps
:用来获取action并派送action
3、在类组件的使用
index.jsx: 创建纯函数和一个状态容器
import {legacy_createStore as createStore} from "redux";
function reducer(state={count:1},action){
switch (action.type){
case'ADD':
return {count:state.count + 1}
case'SUB':
return {count:state.count - 1}
default:
return state
}
}
let store = createStore(reducer);
export default store;
index.js(全局配置文件): 将自定义的store共享给了App及其子组件
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import {Provider} from 'react-redux'
import store from './store'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={ store }> {/*将自定义的store共享给了App及其子组件*/}
<App />
</Provider>
);
action.js:
function add(){
return {
type:'ADD'
}
}
function minus(){
return {
type:'MINUS'
}
}
const action = {add,minus}
export default action;
Counter.jsx
import React from "react";
import {connect} from 'react-redux'
import action from "../store/action";
class Counter extends React.Component{
render() {
return (
<div>
<p>{ this.props.count }</p>
<button onClick={ this.props.add}>加1</button>
<button onClick={this.props.minus}>减1</button>
</div>
)
}
}
const mapStateToProps = state=> state; //获取store的state并传递给props
const mapDispatchToProps = {...action} //获取action并派发出去
//通过connect函数将共享的store和定义好的action传递给Counter组件的props属性
export default connect(mapStateToProps,mapDispatchToProps)(Counter);
App.js:
import logo from './logo.svg';
import './App.css';
import Counter from "./components/Counter";
function App(props) {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
<Counter/>
</div>
);
}
export default App;
4、在函数组件中使用
(1)在React-Redux7.x以后的版本中增加了用于操作React-Redux的Hooks,这些hooks只能在函数组件中使用
(2)组成部分:
A、const state = useSelector(state=>state),功能类似于connect
B、const dispatch = useDispatch(),返回store中的dispatch方法
C、const store = useStore(),返回的是store
其余配置遇上一个示例相同
Counter1.jsx代码段:
import React from "react";
import { useDispatch,useSelector} from "react-redux";
function Counter1(props){
const count = useSelector(state=>state.count)
const dispatch = useDispatch();
return (
<div>
<p>{ count } </p>
<button onClick={()=>{ dispatch({type:'ADD'})}}>加1</button>
<button onClick={()=>{ dispatch({type:'MINUS'})}}>减1</button>
</div>
)
}
export default Counter1;
三、reducer的拆分与合并
1、拆分
一个项目只有一个store,为了便于维护可以将reducer按照模块进行拆分
例如:User(用户数据)、Todo(待办事项)
function userReducer(state={},action){}
function todoReducer(state={},action){}
2、合并
在创建store时将reducer进行合并。使用的方法是
combineReducer({})
const store = createStore(combineReducer({user,todo}))
四、redux-thunk中间件
1、中间件(middleware):Redux的核心操作比较简单。在实际的开发中,当action派发之后,reducer操作之前还要做一些其他的工作。由于reducer是一个纯函数,这些额外的工作他无法完成,所以需要一个中间件。
2、redux-thunk中间件:主要用于解决项目中的异步请求
(1)安装:npm i react-redux
(2)创建store时,引入中间件,redux提供了applyMiddleware来引入
(3)利用中间件完成额外工作