现代Web开发系列教程_04
文章目录
本篇使用redux结合react重写刚才那个很简单的hello world示例。
redux的理念
redux有三个重要的理念:单一数据源、状态是只读的、使用纯函数转换状态。具体见链接
安装redux与react-redux
npm install redux react-redux --save
状态转换纯函数
web-src/js/components/GreetingConstant.js
export const CHANGE_NAME = 'CHANGE_NAME';
web-src/js/reducers/GreetingReducer.js
import {CHANGE_NAME} from '../constants/GreetingConstant.js'
const initialState = {
name: '',
output: ''
}
export function GreetingReducer(state = initialState, action) {
if (typeof state === 'undefined') {
return initialState;
}
switch(action.type) {
case CHANGE_NAME:
return Object.assign({}, state, {
name : action.name,
output: 'Hello, ' + action.name
});
default:
return state;
}
};
这两个文件很简单,GreetingConstant.js
里定义了action类型的常量,GreetingReducer.js
就是一个普通纯函数,它的工作就是根据action转换state。
actionCreator
action
是一个纯对象,其中保存了用来转换state的信息,一般包括type
类型及其它参数,官方是这样定义的Actions are payloads of information that send data from your application to your store.
。
actionCreator
则是产生action
的方法。
web-src/js/actions/GreetingAction.js
import { CHANGE_NAME } from '../constants/GreetingConstant.js'
export function changeName(name) {
return {
type : CHANGE_NAME,
name: name
};
}
组件
在redux与react项目中,组件分为Presentational Components
与Container Components
,有的地方叫Dump Components
与Smart Components
Presentational Components | Container Components | |
---|---|---|
Purpose | How things look (markup, styles) | How things work (data fetching, state updates) |
Aware of Redux | No | Yes |
To read data | Read data from props | Subscribe to Redux state |
To change data | Invoke callbacks from props | Dispatch Redux actions |
Are written | By hand | Usually generated by React Redux |
简单来说Presentational Components
是完全根据props属性决定行为与展现的组件,完成不感知redux的存在。Container Component
则负责从state中抽取属性,分发redux's action
,这里一般会用到redux
的connect
方法,还是看下面的代码。
web-src/js/components/GreetingComponent.js,这个就是一个Presentational Components
组件
import React from 'react'
const noop = function(){};
class GreetingComponent extends React.Component{
constructor(props){
super(props);
this._changeName = this.changeName.bind(this);
}
changeName(e){
this.props.changeName(e.target.value);
}
render() {
return (
<div>
<input value={this.props.name} onChange={this._changeName}/><br/>
<label>{this.props.output}</label>
</div>
);
}
};
GreetingComponent.propTypes = {
changeName: React.PropTypes.func.isRequired,
name: React.PropTypes.string.isRequired,
output: React.PropTypes.string.isRequired
};
GreetingComponent.defaultProps = {
changeName: noop,
name: '',
output: ''
};
export default GreetingComponent;
web-src/js/containers/GreetingContainer.js,这个就是一个Container Component
组件
import { connect } from 'react-redux'
import GreetingComponent from '../components/GreetingComponent.js'
import {changeName} from '../actions/GreetingAction.js'
const mapStateToProps = (state) => {
return {
name: state.name,
output: state.output
}
}
const mapDispatchToProps = (dispatch) => {
return {
changeName: (name) => {
dispatch(changeName(name))
}
}
}
const GreetingContainer = connect(
mapStateToProps,
mapDispatchToProps
)(GreetingComponent)
export default GreetingContainer
web-src/js/components/GreetingApp.js,这个就是一个Presentational Components
组件
import React from 'react'
import GreetingContainer from '../containers/GreetingContainer.js'
export default class GreetingApp extends React.Component{
render(){
return <GreetingContainer/>
}
}
使用Provider
将state与组件关联起来
web-src/js/entries/demo3.js
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import {GreetingReducer} from '../reducers/GreetingReducer.js'
import GreetingApp from '../components/GreetingApp.js'
let store = createStore(GreetingReducer)
render(
<Provider store={store}>
<GreetingApp />
</Provider>,
document.getElementById('reactHolder')
)
这里用到了redux
的Provider
,它会把store附属到组件树的context上,其子组件就都可以访问到store了。
本篇源代码地址
文章作者 Jeremy Xu
上次更新 2016-04-17
许可协议 © Copyright 2020 Jeremy Xu