看了n+1天的react,redux,react-redux,终于有一点点懂了
模仿Counter计数器,写了一个很小很小的ADD功能的DMEO
效果图:
然后贴出我的目录结构:
组件
React-Redux 将所有组件分成两大类:
UI组件: 负责UI呈现,没有任何业务逻辑,不使用任何redux的API,没有state,通过this.props获取数据。
容器组件:负责数据和处理业务逻辑
当一个组件同时有UI和业务逻辑时,拆分成两个部分。里面是用户自定义的UI组件,外面是通过react-redux的connect方法生成的容器组件。容器组件负责把数据通过props传给内部的UI组件。
一:UI-Components
components/Add.js
import React, { Component ,PropTypes} from 'react'
var titStyle={color:'#f00',fontSize:'36px'}
var listStyle={width:'200px',border:'1px solid #ccc'}
class Add extends Component{
render() {
//从组件的props属性中导入一个方法和一个变量
const { add_new, add } = this.props;
//渲染组件
return (
<div>
<div style={titStyle}>this showArea</div>
<ol style={listStyle}>
{add.map(function(item,i){
return (
<li key={i}>
<label>{item}</label>
</li>
)
})}
</ol>
<button onClick={add_new}> Add New </button>
</div>
)
}
}
//限制组件的props安全,指定属性的类型,且必须存在
Add.PropTypes = {
add_new: PropTypes.func.isRequired,
add:PropTypes.string.isRequired
}
export default Add
二:Container-Component
containers/App.js
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import Add from '../components/Add'
import * as AddActions from '../actions/add'
/*定义输入逻辑,state映射到 UI 组件的参数(props)
mapStateToProps是一个函数,接收一个叫state的参数,返回一个对象
mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。*/
function mapStateToProps(state){
console.log(state.handlerList);
return {
add: state.handlerList
}
}
/*定义输出逻辑,mapDispatchToProps用来建立 UI 组件的参数到store.dispatch方法的映射。即定义了哪些用户的操作应该当作 Action,传给 Store。*/
function mapDispatchToProps(dispatch){
return bindActionCreators(AddActions, dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(Add)
上述代码,我们干了几件事:
把state的handlerList值绑定到props上
把action的方法绑定到props上
Action
State 的变化,会导致 View 的变化。
但是,用户接触不到 State,只能接触到 View。
所以,State 的变化必须是 View 导致的。
Action 就是 View 发出的通知,表示 State 应该要发生变化了。
Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。
actions/add.js
export const ADD_NEW = 'ADD_NEW'
export function add_new(payload) {
return {
type: ADD_NEW,
payload : ' new'
}
}
Reducer
store收到一个action后,会重新计算state,这个计算过程就叫reducer,返回一个新的state
reducers/handlerActions.js
import { ADD_NEW } from '../actions/add'
const initialState = ['old','old',] //定义state的初始值
//reducer其实也是个方法而已,参数是state和action,返回值是新的state
export default function handlerList(state = initialState,action){
switch (action.type) {
case ADD_NEW:
return state.concat(action.payload) //新的state
default:
return state
}
}
reducers/index.js
import { combineReducers } from 'redux'
import handlerList from './handlerActions'
//使用redux的combineReducers方法将所有reducer打包起来,这种写法就是 State 的属性名必须与子 Reducer 同名
const rootReducer = combineReducers({
handlerList
//a:handlerList 也可以这样写,不过在App.js中,也要更换为a
})
export default rootReducer
在reducers中,我
写了reducer用于更新state
将所有reducer(这里只有一个)打包成一个reducer
入口文件:index.js
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './src/containers/App'
import configureStore from './src/store/configureStore'
const store = configureStore()
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
provider是react-redux提供的方法。
connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。
React-Redux 提供Provider组件,将store作为provider的属性,可以让容器组件拿到state。
Provider在根组件外面包了一层,这样一来,App的所有子组件就默认都可以拿到state了。