安装
npm install --save redux
npm install --save react-redux
npm install redux-thunk
npm install --save-dev redux-devtools
上面的三个命令分别安装了redux库、React绑定库、redux-thunk中间件和开发者工具
建结构
mkdir actions
mkdir reducers
mkdir components
mkdir containers
mkdir store
上面的命令在根目录下新建了五个文件夹
- actions 存放了所有的动作,在组件中通过diapatch来触发action的方法
- reducers 存放了所有更新state的方法,action方法触发reducer来更新state
- components 存放了所有的组件
- containers 存放了容器组件,通过容器我们把state的值绑定到组件props上,把action创建函数绑定到props上
- store 存放用于注册store的配置文件
基本使用
一个简单的例子,实现一个拉取豆瓣top250电影的列表
新建项目模板文件
touch index.html
在根目录下新建index.html文件作为项目的模板文件,内容如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
<div id="app"></div>
<script src="index.js"></script>
</body>
</html>
新建入口文件
在根目录新建main.js作为我们的入口文件
touch main.js
内容如下
import React from 'react';
import {render} from 'react-dom';
import {Provider} from 'react-redux'
import Douban from './containers/Douban'
import configureStore from './store/configureStore'
const store = configureStore();
render(
<Provider store={store}>
<Douban />
</Provider>,
document.getElementById('app')
)
上面代码中,我们做了几件事情
- 导入了Douban容器组件,这个容器组件是将组件和props结合起来的一个组件
- 注册了store 并放入了Provider组件顶层,并渲染
注册store
touch store/configureStore.js
内容如下
import { createStore,applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import reducer from '../reducers'
//applyMiddleware来自redux可以包装 store 的dispatch
//thunk作用是使action创建函数可以返回一个function代替一个action对象
const createStoreWithMiddleware = applyMiddleware(
thunk
)(createStore)
export default function configreStore(initialStare){
const store = createStoreWithMiddleware(reducer,initialStare)
//热替换选项
if(module.hot){
module.hot.accept('../reducers',()=>{
const nextReducer = require('../reducers')
store.replaceReducer(nextReducer)
})
}
return store
}
新建组件
touch components/Douban.js
在components目录下新建Douban.js组件文件,内容如下
import React from 'react';
export default React.createClass({
render(){
const {title,list,click} = this.props //从组件的props属性中导入两个变量和一个方法
let listHtml = list.map(function(item){
return (<li key={item.id}>{item.title}</li>)
});
return (
<div>
<h1>{title}</h1>
<ul>
{listHtml}
</ul>
<button onClick={click}>获取数据</button>
</div>
)
}
})
上面的代码建立了一个组件,组件的内容是一个标题和一个ul列表,从组件的props属性中导入了两个变量和一个方法。
新建容器文件
touch containers/Douban.js
在容器目录新建了Douban.js文件,内容如下
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Douban from '../components/Douban'
import * as DoubanAction from '../actions/doubanAction'
//将state.douban 绑定到props.douban
function mapStateToProps(state){
return {
douban:state.douban
}
}
//将DoubanAction的所有方法绑定到props上
function mapDispatchToProps(dispatch){
return bindActionCreators(DoubanAction,dispatch)
}
//通过react-redux提供的connect方法将我们需要的state中的数据和actions中的方法绑定到props上
export default connect(mapStateToProps,mapDispatchToProps)(Douban)
上面代码我们干了两件事:
- 把state.douban的值绑定到了props.douban上
- 把action绑定到了props上
- 导出绑定后的组件
新建action
touch actions/douban.js
内容如下
export const DOUBAN_TOP250 = 'DOUBAN_TOP250'
export function douban_list(title='',list=[]){
return {
type:DOUBAN_TOP250,
title:title,
list:list
}
}
//将action的方法绑定到props上
export function getDoubanTop250(){
return (dispatch) => {
$.getJSON("https://api.douban.com/v2/movie/top250?callback=?",function(result){
dispatch(douban_list(result.title,result.subjects))
})
}
}
//这些方法都导出,在其他文件导入的时候,使用import * as actions就可以生成一个actions对象包含所有的export
action负责运算,通知reducer更新state。
新建reducer
touch reducers/douban.js
内容如下
import {DOUBAN_TOP250} from '../actions/douban'
export default function douban(state={title:'',list:[]},action){
switch (action.type){
case DOUBAN_TOP250:
return {title:action.title,list:action.list}
default:
return state
}
}
reducer其实是个方法,参数state和action,返回值是新的state,reducer只负责赋值,actions负责运算
新建reducer打包导出文件
在项目中我们会建立多个reducer文件,所有我们需要一个文件把所有的reducer文件打包导出
touch reducers/index.js
内容如下
import { combineReducers } from 'redux'
import douban from './douban'
const rootReducer = combineReducers({
douban
})
export default rootReducer
上面代码中,我们使用redux的combineReducers方法将所有的reducer打包起来导出
相关文档
https://lewis617.github.io/2016/01/19/r2-counter/
来源:oschina
链接:https://my.oschina.net/u/914061/blog/831743