13.React中使用Redux数据流
1.Redux概述
当页面渲染完成后,UI就已经出现,用户触发了UI上的一些action,action将被送到一个叫Reducer的方法里面去,Reducer将会更新Store,Store中包含state。
使用场景:
组件之间共享信息,例如,用户登录之后客户端会存储用户信息(如userid、头像等),而系统的很多个组件都会用到这些信息,例如收藏、点赞、评论等。因此每个系统都需要一个管理多组间使用的公共信息的功能,这就是Redux的作用。
2.安装
npm install react-redux redux
网站:
http://redux.js.org/
http://cn.redux.js.org/
3.Redux和React集成
-
第一步:创建更新用户信息的Action
我们现在主要做的就是初始化城市信息。
首先判断localStorage中有没有城市信息,如果有,那么我们就要更新redux中的userinfo中的cityname。
这里的action就是一个改变redux存储内容的行为,这里更新redux中的userinfo中的cityname就是我们的action
//这是redux触发数据改变的行为,type类型要和reducer中定义的actiontype相同
//第一步:创建更新用户信息的Action
export function update(data) {
return {
type:'USERINFO_UPDATE',
data
}
}
-
第二步:根据action定义计算规则,即reducer
rootReducer.js是所有规则的入口,可以在这里继续添加其他规则
import {combineReducers} from 'redux'
import userinfo from './userinfo'
//这是redux的第一步定义规则,这是所有规则的入口,可以存放多个规则。
const rootReducer=combineReducers({
userinfo:userinfo
});
export default rootReducer;
userinfo.js是我们定义的一个和用户相关的规则,内容如下:
这里的action就是第一步创建的action,通过action.type来匹配action和reducer
const initialState ={};
//这是和用户信息相关的规则,这里定义了一个更新城市名字的规则
export default function userinfo(state=initialState,action) {
switch (action.type){
//修改城市名字
case 'UPDATE_CITYNAME':
return action.data;
default:
return state;
}
}
-
第三步:根据reducer创建store
import {createStore} from 'redux'
import rootReducer from '../reducer/rootReducer'
//redux第二步,创建store
export default function configureStore(initialState) {
const store = createStore(rootReducer, initialState,
// 触发 redux-devtools
window.devToolsExtension ? window.devToolsExtension() : undefined
);
return store;
}
第四步:监听数据变化
在ReactDom.render的index.jsx页面上,为自己的入口组件添加外层<provider></provider>标签。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import RouterMap from './routerMap';
import registerServiceWorker from './registerServiceWorker';
import {Provider} from 'react-redux'
import configureStore from './store/configStore'
const store=configureStore();
ReactDOM.render(
<Provider store={store}>
<RouterMap/>
</Provider>
,
document.getElementById('root'));
registerServiceWorker();
第五步:为App组件绑定redux react,根据路由规则所有的组件都是App的子组件。所以每次都会先进入App组件
我们在App组件中给Redux初始设置用户信息,然后在其他组件中获得Redux中的用户信息。
- App组件
import React from 'react';
import './App.css';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import * as userInfoActions from './action/userInfoActions'
class App extends React.Component {
constructor() {
super();
this.state = {initDone: false};
}
componentDidMount() {
// 获取位置信息
let cityName = localStorage.cityName;
if (cityName == null) {
cityName = '北京';
}
//触发redux的修改行为
this.props.userInfoActions.update({
cityName: cityName
});
// 更改状态
this.setState({
initDone: true
})
}
//首先判断是否完成初始化
render(){
return (
<div>
{
this.state.initDone ? this.props.children : <div>正在加载</div>
}
</div>
);
}
}
//-------------------redux react 绑定--------------------
//当前组件如需使用redux中的共享数据,在此设置,就能够当作属性来使用
function mapStateToProps(state) {
return {}
}
//触发数据改变
function mapDispatchToProps(dispatch) {
return {
userInfoActions: bindActionCreators(userInfoActions, dispatch),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App)
- 在Home组件中应用这些信息
import React from 'react';
import HomeHeader from '../component/home/homeheader/HomeHeader';
import Category from '../component/home/category/Category';
import Recomment from '../component/home/recommend/Recomment';
import Likelist from '../component/home/likelist/LikeList';
import { connect } from 'react-redux';
class Home extends React.Component{
render(){
return(
<div>
<HomeHeader cityName={this.props.userinfo.cityName}/>
<Category/>
<Recomment/>
<Likelist cityName={this.props.userinfo.cityName}/>
</div>
);
}
}
// -------------------redux react 绑定--------------------
function mapStateToProps(state) {
return {
userinfo: state.userinfo
}
}
//触发数据变化
function mapDispatchToProps(dispatch) {
return {
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Home)
4.异步react-thunk插件的使用
我们希望在页面初始化的阶段,从后台根据用户的username,返回该用户所有的收藏商品id,并存储到redux中。
-
首先定义这个action
//更新收藏列表
export function update(data) {
return {
type:'STORE_UPDATE',
data
}
}
//在App.js中完成页初始化,从后台获取该用户的所有收藏商品id存储到redux中
//这里先fetch从后台获取json,然后触发将json更新到redux的update方法。
export function getInitStore(username) {
return function (dispatch){
console.log('getInitStore执行了');
let option={method:'GET'};
fetch(`/api/store/getStore/${username}`,option)
.then(res => res.json())
.then(json => dispatch(update(json)));
};
}
-
之后根据action定义规则reducer
const initialState =[];
//收藏创建的规则
export default function store(state=initialState,action) {
switch (action.type){
//
case 'STORE_UPDATE':
return action.data;
default:
return state;
}
}
在rootReducer中添加规则store
import {combineReducers} from 'redux'
import userinfo from './userinfo'
import store from './store'
//这是redux的第一步定义规则,这是所有规则的入口,可以存放多个规则。
const rootReducer=combineReducers({
userinfo:userinfo,
store:store
});
export default rootReducer;
-
根据reducer创建redux的存储区
需要安装redux-thunk插件
npm install redux-thunk --save
import thunkMiddleware from 'redux-thunk';
import {createStore,applyMiddleware,compose} from 'redux'
import rootReducer from '../reducer/rootReducer'
//创建store
export default function configureStore(initialState) {
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducer,initialState,
composeEnhancers(applyMiddleware(thunkMiddleware)
));
return store;
}
- 监听数据变化(参考3中第四步)
在ReactDom.render的index.jsx页面上,为自己的入口组件添加外层<provider></provider>标签。 - 在app.js中获得redux的初始值
import React from 'react';
import './App.css';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import * as userInfoActions from './action/userInfoActions'
import * as storeActions from './action/storeActions';
class App extends React.Component {
constructor() {
super();
this.state = {initDone: false};
}
componentDidMount() {
// 获取位置信息
let cityName = localStorage.cityName;
if (cityName == null) {
cityName = '北京';
}
//触发redux的修改行为
this.props.userinfo.cityName=cityName;
this.props.userInfoActions.update(this.props.userinfo);
//获取用户名
let username=localStorage.username;
if(username!=null){
//触发redux的修改行为
this.props.userinfo.username=username;
this.props.userInfoActions.update(this.props.userinfo);
//触发从后台根据username获取个人收藏商品id,存储在redux中
if(this.props.userinfo.username!=null)
//从后台获取收藏信息,触发action
this.props.storeActions.getInitStore(this.props.userinfo.username)
}
// 更改状态
this.setState({
initDone: true
})
}
//首先判断是否完成初始化
render(){
return (
<div>
{
this.state.initDone ? this.props.children : <div>正在加载</div>
}
</div>
);
}
}
//-------------------redux react 绑定--------------------
//当前组件如需使用redux中的共享数据,在此设置,就能够当作属性来使用
function mapStateToProps(state) {
return {
userinfo: state.userinfo,
store:state.store
}
}
//触发数据改变
function mapDispatchToProps(dispatch) {
return {
userInfoActions: bindActionCreators(userInfoActions, dispatch),
storeActions: bindActionCreators(storeActions, dispatch)
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App)