1、redux
redux 是类似vuex的状态管理组件 使用 createStore创建store来管理
具体使用如下:
import { createStore, compose, applyMiddleware } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose
const enhancer = composeEnhancers(
applyMiddleware(thunk) // 使用thunk中间件
)
const store = createStore(reducer, enhancer)
export default store
注意:在使用devtools时需要用到composeEnhancers来使用,中间件需要使用 applyMiddleware,redux-thunk接下来在详细说明
store目录下
actionTypes.js
actionCreator.js
index.js
reducer.js
1.actionTypes.js
记录action常量,保证不会出错(类似vuex中Mutations)
export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_LIST = 'add_todo_list';
export const DELETE_ITEM = 'delete_item';
export const INIT_LIST = 'init_list';
2.actionCreators.js
action创建管理,返回一个action,这里理解为类似vuex中的action
import * as types from './actionTypes';
import axios from 'axios';
export const getTodoLists = (value) => ({
type: types.INIT_LIST,
value
})
// 这里用到了redux-thunk来保证可以返回一个函数类型的action来执行ajax异步请求
export const initList = () => {
return (dispatch) => {
axios.post('/api/todolist').then((res) => {
dispatch(getTodoLists(res.data.data));
}).catch(() => {
dispatch(getTodoLists(['暂无数据']));
})
}
}
3.reducer.js
reducer相当于记录本,store的处理器,用于接收所有action并处理数据,设置state
import { ADD_ITEM, CHANGE_INPUT, DELETE_ITEM } from './actionTypes'
const defaultState = {
inputValue: '123',
list: []
}
export default (state = defaultState, action) => {
if (action.type === CHANGE_INPUT) {
const newState = JSON.parse(JSON.stringify(state))
newState.inputValue = action.value
return newState
}
if (action.type === ADD_ITEM) {
const newState = JSON.parse(JSON.stringify(state))
newState.list.push(newState.inputValue)
newState.inputValue = ''
return newState
}
if (action.type === DELETE_ITEM) {
const newState = JSON.parse(JSON.stringify(state))
newState.list.splice(action.index, 1)
return newState
}
return state
}
但随着业务的增多,reducer不可能一直写下去,这里就要分模块进行处理,类似vuex中的modules,每个模块自己处理自己的state,action,reducer等,这里就要使用react-redux来进行配置
2、react-redux
在React-redux 中有两个比较关键的概念:Provider和connect方法。
Provider
一般我们都将顶层组件包裹在Provider组件之中,这样的话,所有组件就都可以在react-redux的控制之下了,但是store必须作为参数放到Provider组件中去
import { Provider } from 'react-redux'
function App() {
return (
<Provider store={store}>
<Header/>
</Provider>
)
}
这个组件的目的是让所有组件都能够访问到Redux中的数据。
connect方法
在组件内使用
import React from 'react'
import { connect } from 'react-redux'
import { getAddItemAction, getDeleteItemAction, getInputChangeAction } from './store/actionCreator' // connect可以获取store
const TodoList = (props) => {
const { inputValue, list, handleInputChange, handleClick, handleDelete } = props
return (
<div>
<input value={inputValue} onChange={handleInputChange}/>
<button onClick={handleClick}>add</button>
<ul>
{
list.map((item, index) => {
return (
<li key={index} onClick={handleDelete}>{item}</li>
)
})
}
</ul>
</div>
)
}
// 映射store 的state
const mapStateToProps = (state) => {
return {
inputValue: state.inputValue,
list: state.list
}
}
// 映射store dispatch
const mapDispatchToProps = (dispatch) => {
return {
handleInputChange(e) {
const action = getInputChangeAction(e.target.value)
dispatch(action)
},
handleClick() {
const action = getAddItemAction()
dispatch(action)
},
handleDelete(index) {
const action = getDeleteItemAction(index)
dispatch(action)
}
}
}
// 表示让组件和store做连接,必须保证当前组件在Provider组件中
// content第一个参数,是连接规则,即把state映射为props中的数据,优点类似Vue中的getter
// 第二个参数是派发映射关系,即将store.dispatch映射至某个方法里
// TodoList是ui组件,但是通过connect连接后,返回的结果就是个容器组件(包含数据和方法)
export default connect(mapStateToProps, mapDispatchToProps)(TodoList)
根目录store中的reducer就可以这么拆分
import { combineReducers } from 'redux'
import { reducer as headerReducer } from '../components/Header/store'
import { reducer as homeReducer } from '../pages/home/store'
import { reducer as detailReducer } from '../pages/detail/store'
import { reducer as loginReducer } from '../pages/login/store'
// 类似于vuex的module合并,会将这部分的内容封装至不同的参数下单独管理即header:{header单独的state状态管理}
export default combineReducers({
header: headerReducer,
home: homeReducer,
detail: detailReducer,
login: loginReducer
})
PureComponent 与 Compnent 的使用
当组件中使用redux 时, 组件需要与 react-redux 中的 connect 配合使用,当store中的数据发生变化的时候, 每个组件都会重新渲染, 这显然不是我们想要的,我们可以使用生命周期的钩子shouldComponentUpdate 判断是否需要重新渲染,但是我们最好配合 react 中的PureComponent 使用, 将class App extends Compnent 中的 Compnent 换成 PureComponent 就可以解决 。
class Home extends PureComponent
// 继承了PureComponent,下方的判断即可省略
shouldComponentUpdate(nextProps, nextState, nextContext) {
return this.props.data !== nextProps.data
}
3、react-thunk
是一个辅助action可以派发ajax时间函数的中间件,使用非常简单
只需要在store创建的时候使用applyMiddleware创建即可
import { createStore, compose, applyMiddleware } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose
const enhancer = composeEnhancers(
applyMiddleware(thunk) // 使用thunk中间件
)
const store = createStore(reducer, enhancer)
export default store
在action创建管理,就可以返回一个函数来辅助ajax请求响应
import * as types from './actionTypes';
import axios from 'axios';
// 正常的需要返回一个对象,来提供dispatch派发action
export const getTodoLists = (value) => ({
type: types.INIT_LIST,
value
})
// 这里用到了redux-thunk来保证可以返回一个函数类型的action来执行ajax异步请求
export const initList = () => {
return (dispatch) => {
axios.post('/api/todolist').then((res) => {
dispatch(getTodoLists(res.data.data));
}).catch(() => {
dispatch(getTodoLists(['暂无数据']));
})
}
}
相关连接
最近在学习react开发,整理几篇笔记方便自己查询使用,下面是连接地址
1.React 之 react-transition-group
2.React之 redux、react-redux、redux-thunk