写在前面
在react中使用redux一直是一大痛点,redux 过于复杂 所以后来出现了mobx,当然今天不说mobx,今天说下redux(自以为很复杂的redux)。
? ? ? ? ?redux的基本用法就是:用户发出 Action,Reducer 函数算出新的 State,View 重新渲染。但是现在有一个问题就是,异步操作怎么办?Action 发出以后,Reducer 立即算出 State,这叫做同步;Action 发出以后,过一段时间再执行 Reducer,这就是异步。
? ? ? ? ?怎么才能 Reducer 在异步操作结束后自动执行呢?这就要用到新的工具:中间件(middleware)。本次用到的中间件有redux-thunk,redux-logger
? ? ? ? ?
-
安装四个npm包
npm install --save redux react-redux redux-thunk
npm install --save-dev redux-logger
redux 和 react-redux 是必须的 redux-thunk可以帮你实现异步action。redux-logger可以实现监测redux的变化
-
文件结构

然后我们在详细介绍一下每个文件所做的事情
-
actions.js
export const SET_PAGE_TITLE = "SET_PAGE_TITLE";
export const SET_INFO_LIST = "SET_INFO_LIST";
export function setPageTitle(data){
return {type: SET_PAGE_TITLE,data: data}
}
export function setInfoList (data) {
return (dispatch,getState) => {
// 使用fetch实现异步请求
// 请求发起前可以先dispatch一个加载开始状态
// 例如 dispatch({ type: SET_LOADING_TYPE,data: "loading" })
window.fetch(‘/api/getInfoList‘,{
method: ‘GET‘,headers: {
‘Content-Type‘: ‘application/json‘
}
}).then(res => {
return res.json()
}).then(data => {
let { code,data } = data
if (code === 0) {
dispatch({ type: SET_INFO_LIST,data: data })
}
// 请求结束可以dispatch一个加载结束状态
// 例如 dispatch({ type: SET_LOADING_TYPE,data: "loaded" })
// 还可以区分一下成功或者失败
})
}
}
可以看出第一个action 是直接返回了一个action:{type: SET_PAGE_TITLE,data: data} ,而第二个则返回了一个函数,这个函数接受两个参数 dispatch 与 getState? , dispatch可以在异步加载完成以后发出一个action。在不使用redux-thunk这个中间件的时候dispatch接受的只能是一个action , 使用这个中间件就可以接受上文所说的参数,也就实现了Reducer 在异步操作结束后自动执行。
-
reducers.js
// reducers.js
// combineReducers 工具函数,用于组织多个reducer,并返回reducer集合
import {combineReducers} from ‘redux‘
import defaultState from ‘./state‘
import {SET_PAGE_TITLE,SET_INFO_LIST} from ‘./actions‘
//一个reducer 就是一个函数
function pageTitle ( state = defaultState.pageTitle,action){
// 不同的action 有不同的处理逻辑
switch (action.type) {
case SET_PAGE_TITLE:
return action.data
default:
return state
}
}
function infoList (state = defaultState.infoList,action){
switch (action.type) {
case SET_INFO_LIST:
return action.data
default:
return state
}
}
export default combineReducers({
pageTitle,infoList
})
-
state.js
/**
此文件存放state默认值
同步数据:pageTitle
异步数据:infoList(将来用异步接口获取)
*/
export default {
pageTitle:"首页",infoList:[]
}
-
index.js
// index.js
// applyMiddleware: redux通过该函数来使用中间件
// createStore: 用于创建store实例
import { applyMiddleware,createStore } from ‘redux‘
// 中间件,作用:如果不使用该中间件,当我们dispatch一个action时,需要给dispatch函数传入action对象;但如果我们使用了这个中间件,那么就可以传入一个函数,这个函数接收两个参数:dispatch和getState。这个dispatch可以在将来的异步请求完成后使用,对于异步action很有用
import thunk from ‘redux-thunk‘
import logger from ‘redux-logger‘
// 引入reducer
import reducers from ‘./reducers.js‘
// 创建store实例 第一个参数是reducer集合(reducers),第二个参数初始化的store(initialState),第三个参数是applyMiddleware函数,来使用中间件 ,因为只在reducer里面初始化了值,所以这里并没有传入初始化store的值
let store = createStore(
reducers,applyMiddleware(thunk,logger)
)
export default store
-
入口文件
import React from ‘react‘;
import ReactDOM from ‘react-dom‘;
import {BrowserRouter as Router,Route} from "react-router-dom";
import {Provider} from "react-redux";
import store from ‘./store‘
import App from ‘./App‘
import * as serviceWorker from ‘./serviceWorker‘;
ReactDOM.render(
<Provider store={store}>
<Router >
<Route component={App} />
</Router>
</Provider>,document.getElementById(‘root‘));
// If you want your app to work offline and load faster,you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();
-
test.js
// Test.jsx
import React,{ Component } from ‘react‘
import {Route,Link} from ‘react-router-dom‘
// connect方法的作用:将额外的props传递给组件,并返回新的组件,组件在该过程中不会受到影响
import { connect } from ‘react-redux‘
// 引入action
import { setPageTitle,setInfoList } from ‘../store/actions.js‘
class Test extends Component {
constructor(props) {
super(props)
this.state = {}
}
componentDidMount () {
let { setPageTitle,setInfoList } = this.props
// 触发setPageTitle action
setPageTitle(‘新的标题‘)
// 触发setInfoList action
setInfoList([{data:1}])
}
render () {
// 从props中解构store
let { pageTitle,infoList } = this.props
// 使用store
return (
<div>
<div>
<Link to="/courses/ii">Courses</Link>
</div>
<h1>{pageTitle}</h1>
{
infoList.length > 0 ? (
<ul>
{
infoList.map((item,index) => {
return <li key={index}>{item.data}</li>
})
}
</ul>
):null
}
</div>
)
}
}
// mapStateToProps:将state映射到组件的props中
const mapStateToProps = (state) => {
return {
pageTitle: state.pageTitle,infoList: state.infoList
}
}
// mapDispatchToProps:将dispatch映射到组件的props中
const mapDispatchToProps = (dispatch,ownProps) => {
return {
setPageTitle (data) {
// 如果不懂这里的逻辑可查看前面对redux-thunk的介绍
dispatch(setPageTitle(data))
// 执行setPageTitle会返回一个函数
// 这正是redux-thunk的所用之处:异步action
// 上行代码相当于
/*dispatch((dispatch,getState) => {
dispatch({ type: ‘SET_PAGE_TITLE‘,data: data })
)*/
},setInfoList (data) {
dispatch(setInfoList(data))
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Test)
代码的重点在connect函数。这个函数也是由react-redux提供的。使用它可以包装普通的展示组件(这里的Test——只负责展示数据),然后返回一个容器组件。connect函数通过第一个参数让展示组件订阅了来自store的数据;通过第二个参数让展示组件默认可以dispatch各种action。
?applyMiddlewares()
applyMiddlewares是redux的原生方法,作用是将所有中间件组成一个数组,依次执行。
要注意的是中间件为顺序有要求,具体可以查看你下载的npm包介绍。
本次使用的redux-logger 必须放最后,不然可能监测不到正确的store
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|