题目:redux的使用教程
前言:学习react的过程中一定会碰到redux,我在学习redux的时候,每每感觉自己记住了,但是用的时候,感觉总是不知如何写起,或者会用的时候总会出错,所以打算写一篇redux的教程,把自己在学习和使用过程中的心得记录下来。
一:认识redux官网
:redux中文网
我的理解:redux是一个独立的(也就是说它并不属于react,在其他框架下也都是可以使用的),开源的,第三方的集中式的状态管理器。提供可预测的状态管理。
二:为什么
那么我们为什么要使用redux呢?
这就不得不提到我们在react中最常见的行为之一,组件之间的通信,我们顺便把组件之间的通信复习一下。
父 —> 子 props 直接通过prop传递
子 —> 父 props 父组件传递函数prop,子组件调用这个函数进而传参。
爷 —> 孙 props 或者是 context context为我们提供了Provider 和 Consumer
孙 —> 爷 props 或者是 context 也是通过函数的形式传递参数
兄 —> 弟
状态提升 也就是说可以通过把状态提升到他们共同的父组件上进行维护,也就是变相的父–> 子 子 —> 父
或者使用eventBus模式,创建一个公共的容器,然后利用发布订阅模 式进行传递信息也可以。
我们可以清楚的知道以上的方式,如果是简单的关系
例如:父子之间,那还好,但是一旦关系变得复杂我们就不得不采取一些额外操作进行管理状态,如果某个状态需要被所有组件共享,那需要做很多繁琐而又重复的劳动,因此我们急需一种可以共享状态的,轻量的东西来帮助我们解决这个问题,而redux就是为这样的问题应运而生。
三、如何使用
准备环境creat-react-app redux-demo
删掉不需要用到的代码 创建如下的目录
|--src
| |--class-com
| |--|--home.jsx
| |--|--about.jsx
| |--fun-com
| |--|--home.jsx
| |--|--about.jsx
| |--store
|--App.js
|--index.js
在sotre目录下先创建一个index.js用于封装集中管理的容易
redux的思想是这样的,所有UI组件都有触发状态更新的可能,因此每个UI组件都可以通过一个方式来更新状态,而为了让更新状态的方式更加容易维护,并且清晰明了,我们规定了触发更新的动作叫做dispatch(分发),分发的时候我们怎么区分呢?原来分发的时候它需要有两个固定的概念,一个是分发的类型,一个是分发的内容,我们把这个叫做分发对象,用代码表示可以这样写:
dispatch({
type:'分发的类型',
state:'分发的内容'
})
我们每一个UI组件都可以通过类似这样的方式进行分发,改变状态,因此UI组件只是起到一个分发的作用。
接下来分发的内容会交给我们的store,store会将分发的分发对象交给reducer来执行,实际上真正干活的是这个reducer。
这个reducer接受两个参数,一个是上一次的state,一个就是分发对象,根据不同的分发对象类型,就可以返回不同的值来真正改变store所维护的状态。
所以reducer的代码可以是这个样子:
const defaultState = {
count: 0
}
function reducer (state = defaultState, action) {
switch (action.type) {
case 'add':
return { ...state, count: state.count + action.count }
case 'mins':
return { ...state, count: state.count - action.count }
default:
return state
}
}
我们继续说回store。store是一个集中式的容器。我们借助redux来创建它。
import { createStore, applyMiddleware } from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store
四、完整代码
我们先将完整的代码奉上,看一下效果,我们先将类式组件的完善一下。npm install react-redux
npm install redux-thunk
安裝以上两个依赖
//App.js
import React, { Component } from 'react'
import './App.css'
import { connect } from 'react-redux'
import About from './class-com/about'
import Home from './class-com/home'
class App extends Component {
render() {
const { count } = this.props
return (
<div className="App">
<span>store:{count}</span>
<h1>Home</h1>
<Home/>
<h1>About</h1>
<About/>
</div>
)
}
}
const mapStateToProps = (state)=>({count:state.count})
export default connect(mapStateToProps)(App)
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root'));
//home.js
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { genAdd , genMins , genAsync } from '../store/action'
class about extends PureComponent {
state = {count:0 , store:0}
change = (e)=>{
this.setState({count:Number(e.target.value)})
}
render() {
const { add , mins , async , count:state } = this.props
// console.log(add ,mins , async , state);
const { count } = this.state
return (
<div>
store:{ state }
<div>
<input type="text" value={count} onChange={this.change}/>
<div>
<button onClick={()=>add(count)}>加</button>
<button onClick={()=>mins(count)}>减</button>
<button onClick={()=>async(count)}>异步加</button></div>
</div>
</div>
)
}
}
const mapStateToProps = (state)=>{
return {
count:state.count
}
}
const mapDispatchToProps = (dispatch)=>{
return {
add:(count)=>{
return dispatch(genAdd(count))
},
mins:(count)=>{
return dispatch(genMins(count))
},
async:(count)=>{
return dispatch(genAsync(count))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(about)
about.js和home.js除了名字以外是一模一样的。
以上组件的逻辑写好了。
接下来创建这样的目录
store
|--const.js
|--index.js
|--action.js
|--reducer.js
//index.js
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import reducer from './reducer'
const enhancer = applyMiddleware(thunk)
const store = createStore(reducer, enhancer)
export default store
//const.js
export const ADD = 'app/ADD'
export const MINS = 'app/MINS'
export const ASYNCADD = 'app/ASYNCADD'
//reducer.js
import { ADD, MINS } from './const'
const defaultState = {
count: 0
}
function reducer (state = defaultState, action) {
switch (action.type) {
case ADD:
return { ...state, count: state.count + action.count }
case MINS:
return { ...state, count: state.count - action.count }
default:
return state
}
}
export default reducer
// action.js
import { ADD, MINS } from './const'
const getNum = (num) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(num);
}, 1000)
})
}
export const genAdd = (payload) => ({ type: ADD, count: payload })
export const genMins = (payload) => ({ type: MINS, count: payload })
export const genAsync = (payload) => {
return async (dispatch) => {
const num = await getNum(payload)
return dispatch(genAdd(num))
}
}
以上就是搭建的整个Demo了,如果不出意外的情况下,就会想以下的效果那样。
store中的状态会被全局共享,并且可以在任意组件中进行改变。
结语:实际上,react-redux还有函数式的一系列hooks可以进行使用。我们下次再分享函数式的redux如何使用。