6.1 Redux成员及其数据流
- actions
actions是描述操作的对象,调⽤dispatch时需要传⼊此对象 - store
store是整个应⽤的数据存储仓库,把我们全局管理的状态数据存储起来 - reducers
reducers接收action并更新store
注意:redux是⼀个单独的数据流框架,是JavaScript的状态容器, 跟react并没有直接的联系,通过redux, 我们可以轻松的对状态进行管理。我们也可以在JQuery在其他的复杂项⽬⾥使⽤redux进⾏数据管理,当我们不知道是否应该是⽤redux的时候,我们都是不需要的,因为只有我们很肯定redux能帮助我们管理好复杂项⽬数据流的时候他才能发挥它的威⼒,简单的项⽬我们只需要state+props+context就够了
Redux数据流的⾛向:
6.2 编写⼀个累加器程序
- 安装redux
npm install redux --save - 使⽤redux的步骤
- 从redux引⼊createStore⽤来创建数据仓库store
createStore(reducers[,initialState])
createStore是⼀个函数,需要传⼊reducer作为参数,返回值是我们需要的store
initialState初始状态,是可选参数
- 在使⽤⻚⾯引⼊数据仓库store
通过getState()⽅法可以获取到数据仓库⾥的状态数据state
通过dispatch(action)可以触发更改reducer函数
每次触发dispatch都会触发store.subscribe()⽅法,⽤来重新触发⻚⾯渲染
store.js
import { createStore } from 'redux'
const firstReducer = (state = 0, action) => {
switch (action.type) {
case 'add':
return state + 1
case 'reduce':
return state - 1
default:
return state
}
}
//创建数据仓库,把我们编写的reducer作为参数传入createStore
const store = createStore(firstReducer)
export default store
App.js
import './App.css'
import { Button } from 'antd'
import store from './store'
import React, { Component } from 'react'
export default class App extends Component {
render() {
return (
<div>
<h1>redux累加器</h1>
{store.getState()}
<div>
<Button onClick={()=>store.dispatch({type:'add'})}>加一</Button>
<Button onClick={()=>store.dispatch({type:'reduce'})}>减一</Button>
</div>
</div>
)
}
}
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App';
import * as serviceWorker from './serviceWorker'
import store from './store'
const render=()=>{
ReactDOM.render(<App />, document.getElementById('root'))
}
render()
serviceWorker.unregister()
//监听数据变化来自动渲染
store.subscribe(render)
6.3 React封装的react-redux进⾏改造累加器
上面每次都要重新调用render,太繁琐。
- 安装react-redux:
npm install react=redux --save - React-redux提供了两个api
Provider 顶级组件,功能为给我们提供数据
connect ⾼阶组件,功能为提供数据和⽅法
store.js不用改
App.js
import './App.css'
import { Button } from 'antd'
import React, { Component } from 'react'
import { connect } from 'react-redux'
//写一个返回数据的方法,供connect使用,connect会把数据转换成props
const mapStateToProps = state => {
return {
count: state
}
}
//写一个dispatch方法,用connect使用,connect会把dispatch转换成props
const mapDispatchToProps = dispatch => {
return {
add: () => dispatch({ type: 'add' }),
reduce: () => dispatch({ type: 'reduce' })
}
}
class App extends Component {
render() {
return (
<div>
<h1>redux累加器</h1>
{this.props.count}
<div>
<Button onClick={() => this.props.add()}>加一</Button>
<Button onClick={() => this.props.reduce()}>减一</Button>
</div>
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import store from './store'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
{' '}
<App />
</Provider>,
document.getElementById('root')
)
6.4 使用⾼阶组件装饰器模式进⾏简化封装代码
修改App.js
import './App.css'
import { Button } from 'antd'
import React, { Component } from 'react'
import { connect } from 'react-redux'
//装饰器
@connect(
state => ({ count: state }),
dispatch => ({
add: () => dispatch({ type: 'add' }),
reduce: () => dispatch({ type: 'reduce' })
})
)
class App extends Component {
render() {
return (
<div>
<h1>redux累加器</h1>
{this.props.count}
<div>
<Button onClick={() => this.props.add()}>加一</Button>
<Button onClick={() => this.props.reduce()}>减一</Button>
</div>
</div>
)
}
}
export default App
6.5 redux中间件
由于redux reducer默认只⽀持同步,实现异步任务或者延时任务时,我们就要借助中间件middleware的⽀持了
redux数据流:
两个中间件:
- redux-thunk ⽀持我们reducer在异步操作结束后⾃动执⾏
安装 redux-thunk
npm install redux-thunk --save - redux-logger 打印⽇志记录协助本地调试
安装redux-logger
npm install redux-logger --save
store.js
import {createStore,applyMiddleware} from 'redux'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
const firstReducer=(state=0,action)=>{
console.log(action)
switch(action.type){
case 'add':
return state+1;
case 'reduce':
return state-1;
default:
return state;
}
}
//创建数据仓库,把编写的reducer作为参数传入createStore
//注意:logger最好放在最后,日志最后输出才不会出bug,因为中间件按顺序执行
const store=createStore(firstReducer,applyMiddleware(thunk,logger))
export default store
6.6 抽离出reducer和action
新建count.redux.js文件存放我们抽离出的reducer和action
count.redux.js
const firstReducer = (state = 0, action) => {
console.log(action)
switch (action.type) {
case 'add':
return state + 1
case 'reduce':
return state - 1
default:
return state
}
}
const add = () => ({ type: 'add' })
const reduce = () => ({ type: 'reduce' })
const asyncAdd = () => dispatch => {
setTimeout(() => {
dispatch({ type: 'add' })
}, 1000)
}
export { firstReducer, add, reduce, asyncAdd }
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import * as serviceWorker from './serviceWorker'
import { Provider } from 'react-redux'
import { firstReducer } from './count.redux'
import { createStore, applyMiddleware } from 'redux'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
const store = createStore(firstReducer, applyMiddleware(thunk, logger))
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
serviceWorker.unregister()
App.js
import './App.css'
import { Button } from 'antd'
import React, { Component } from 'react'
import { connect } from 'react-redux'
import {add,reduce,asyncAdd} from './count.redux'
@connect(
state => ({ count: state }),
{add,reduce,asyncAdd}
)
class App extends Component {
render() {
return (
<div>
<h1>redux累加器</h1>
{this.props.count}
<div>
<Button onClick={() => this.props.add()}>加一</Button>
<Button onClick={() => this.props.reduce()}>减一</Button>
<Button onClick={() => this.props.asyncAdd()}>延迟加一</Button>
</div>
</div>
)
}
}
export default App