UI组件和容器组件
在这个例子中,我们想要分离UI组件和容器组件
//===>src/TodoList.js
import React, { Component } from 'react'
import 'antd/dist/antd.css';
import store from './store/index.js'
import { getInputChangeAction, getAddItemAction, getDeleteItemAction } from './store/actionCreators'
import TodoListUI from './TodoListUI'
class TodoList extends Component {
constructor(props) {
super(props);
this.state = store.getState()
this.handleInputChange = this.handleInputChange.bind(this)
this.handleStoreChange = this.handleStoreChange.bind(this)
this.handleBtnClick = this.handleBtnClick.bind(this)
this.handleItemDelete = this.handleItemDelete.bind(this)
store.subscribe(this.handleStoreChange)
}
render() {
return <TodoListUI
inputValue={this.state.inputValue}
list={this.state.list}
handleInputChange={this.handleInputChange}
handleBtnClick={this.handleBtnClick}
handleItemDelete={this.handleItemDelete} />
}
handleInputChange(e) {
const action = getInputChangeAction(e.target.value)
store.dispatch(action)
}
handleStoreChange(e) {
this.setState(store.getState())
}
handleBtnClick(e) {
const action = getAddItemAction()
store.dispatch(action)
}
handleItemDelete(index) {
const action = getDeleteItemAction(index)
store.dispatch(action)
}
}
export default TodoList
//===>src/TodoListUI.js
import React, { Component } from 'react'
import { Input, Button, List } from 'antd';
class TodoListUI extends Component {
render() {
console.log("***", this.props)
return (
<div style={{ marginTop: '10px', marginLeft: '10px' }}>
<div>
<Input
value={this.props.inputValue}
placeholder="todo info"
style={{ width: '300px', marginRight: '10px' }}
onChange={this.props.handleInputChange} />
<Button type="primary" onClick={this.props.handleBtnClick}>提交</Button>
</div>
<List
style={{ marginTop: '10px', width: '300px' }}
bordered
dataSource={this.props.list}
renderItem={(item, index) => (<List.Item onClick={() => { this.props.handleItemDelete(index) }}>{item}</List.Item>)}
/>
</div>
)
}
}
export default TodoListUI

无状态组件
因为上面TodoListUI这个组件中,只有一个render函数,所以我们可以把它定义成为一个无状态组件(性能最优)
修改TodoListUI
//===>src/TodoListUI.js
import React, { Component } from 'react'
import { Input, Button, List } from 'antd';
const TodoListUI = (props) => {
return (
<div style={{ marginTop: '10px', marginLeft: '10px' }}>
<div>
<Input
value={props.inputValue}
placeholder="todo info"
style={{ width: '300px', marginRight: '10px' }}
onChange={props.handleInputChange} />
<Button type="primary" onClick={props.handleBtnClick}>提交</Button>
</div>
<List
style={{ marginTop: '10px', width: '300px' }}
bordered
dataSource={props.list}
renderItem={(item, index) => (<List.Item onClick={() => { props.handleItemDelete(index) }}>{item}</List.Item>)}
/>
</div>
)
}
export default TodoListUI
Redux 中发送异步请求获取数据
1.添加一个收到请求的actionTypes
//===>src/store/actionTypes.js
...
export const INIT_LIST_ACTION = 'init_list_action';
2.编写一个收到请求的actionCreators
//===>src/store/actionCreators.js
...
export const initListAction = (data) => ({
type:INIT_LIST_ACTION,
data
})
3.编写收到action的reducer的操作
//===>src/store/reducer.js
...
if (action.type === INIT_LIST_ACTION) {
const newState = JSON.parse(JSON.stringify(state))
newState.list = action.data
return newState
}
...
4.编写异步请求逻辑,并触发action
//===>src/TodoList.js
...
componentDidMount() {
axios.get('/list.json').then((res) => {
const data = res.data
const action = initListAction(res.data)
store.dispatch(action)
})
}
...

使用Redux-thunk中间件实现ajax数据请求
1.先来安装redux-thunk
npm install redux-thunk
thunk是redux实现异步请求的中间件
2.怎么使用中间件呢?我们可以参考一下文档
//===>src/store/index.js
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import reducer from './reducer'
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(thunk),
// other store enhancers if any
);
const store = createStore(reducer, enhancer);
export default store;
3.编写一个用于异步请求的action
之前,我们的action是对象,但在这里,因为使用了redux-thunk,我们可以把action写成一个函数。这样的话,我们在使用actionCreator的时候,会先的调用这个函数进行异步操作,之后,在进行后面的操作。
//===>src/store/actionCreators
...
export const getTodoList = () => {
return (dispatch) => {
axios.get('/list.json').then((res) => {
const data = res.data
const action = initListAction(data)
dispatch(action)
})
}
}
4.修改TodoList组件中的钩子函数,进行异步请求
//===>src/TodoList.js
...
import { getInputChangeAction, getAddItemAction, getDeleteItemAction, getTodoList } from './store/actionCreators'
...
componentDidMount() {
const action = getTodoList()
store.dispatch(action)
}
...
效果和之前的异步请求一样
什么是Redux的中间件

Redux-saga中间件使用入门
redux-sage也是用来处理异步请求的,但是超级麻烦。他的github是redux-saga
1.安装redux-sage
npm install redux-saga
2.在项目中引入redux-sage
sagaMiddleware.run(todoSaga)这句话的意思是运行todoSage,也就是第三步中我们要编写的sages.js文件
//===>src/store/index.js
import { createStore, applyMiddleware, compose } from 'redux'
import reducer from './reducer'
import createSagaMiddleware from 'redux-saga'
import todoSaga from './sagas'
const sagaMiddleware = createSagaMiddleware()
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(sagaMiddleware),
// other store enhancers if any
);
const store = createStore(reducer, enhancer);
sagaMiddleware.run(todoSaga)
export default store;
3.在步骤2中,我们引入了sagas这个文件,这个是要我们来自己创建的
这里function*(){}叫做generator函数,你可以百度一下。takeEvery方法可以监听到GET_INIT_LIST这个类型的action,去判断是否要执行getInitList
function* getInitList(){}方法里面的东西可以同步执行,但注意一下异常处理
//===>src/store/sages.js
import { put, takeEvery } from 'redux-saga/effects'
import { GET_INIT_LIST } from './actionTypes'
import { initListAction } from './actionCreators'
import axios from 'axios'
function* getInitList() {
try {
const res = yield axios.get('./list.json')
const action = initListAction(res.data)
yield put(action)
} catch (e) {
console.log('list.json 网络请求失败');
}
}
//generator 函数
function* mySaga() {
yield takeEvery(GET_INIT_LIST, getInitList);
}
export default mySaga;
4.接下来我们就可以编写之前的发送action的操作了
//===>src/store/actionTypes.js
...
export const GET_INIT_LIST = 'get_init_list';
//===>src/store/actionCreators.js
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM, INIT_LIST_ACTION, GET_INIT_LIST } from './actionTypes'
...
export const getInitList = () => ({
type: GET_INIT_LIST
})
//===>src/TodoList.js
import { getInputChangeAction, getAddItemAction, getDeleteItemAction, getInitList } from './store/actionCreators'
...
componentDidMount() {
const action = getInitList();
store.dispatch(action)
}
...

网友评论