初探react-redux
什么是Redux
-
Redux
是JavaScript
状态容器,它提供对状态的统一管理 -
Redux
除了和React
一起用外,还支持其它界面库,如果需要在React
中使用,需要单独安装react-redux
-
react-redux
是一个能过够让Redux
在React
项目中使用的第三方库
Redux
需要关注的有:Action,Reducer,StoreAction
Action
主要用来管理一些分发出去的动作。Action
本质上是一个普通对象,action
内必须使用一个字符串类型的 type
字段来表示将要执行的动作,当应用规模越来越大时,建议使用单独的模块或文件来存放 action
。如下:redux/action/index.tsx
// 为了后期项目的可维护,把所有的action都写在单独文件
const ACTION = {
CHANGEVALUE: (obj:any) => {
return {
type: 'CHANGEVALUE',
value: obj.value
}
},
DECREASE: {
type: 'DECREASE'
},
INCREASE: {
type: 'INCREASE'
}
}export default ACTION
Reducer
Reducer
主要指定了一些如何改变store
中状态的方法:如下redux/reducers/index.tsx
interface IInitState {
count: number
}
interface IActionType {
type: string,
value: string
}export default function reducers (state: IInitState , action: IActionType) {
// 这里是根据传入动作的type,来对Redux中的state进行状态值修改
switch (action.type) {
case 'INCREASE':
return { count: ++state.count }
break
case 'DECREASE':
return { count: --state.count }
break
case 'CHANGEVALUE':
return {count: action.value}
break
default:
return { count: state.count }
}
}
Store
Store
就是将Action
和Reducer
联系起来,使得可以通过Action
来修改State
主要API:
- getState(),返回应用当前的 state 树。
- dispatch(action),分发 action,这是触发 state 状态值改变
- subscribe(listener),添加一个变化监听器。每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。如果需要解绑这个变化监听器,执行 subscribe 返回的函数即可。
- replaceReducer(nextReducer),替换 store 当前用来计算 state 的 reducer。
redux/store/index.tsx
import { createStore } from 'redux'
import reducer from '../reducers'export const initState = {
count: 0
}
// createStore 方法详见Redux API文档:http://www.redux.org.cn/docs/api/createStore.html
const store = createStore(reducer, initState)export default store
现在react-redux的使用redux
的工作已经完成了。我们可以在react文件中直接引入:import store from '../redux/store/index.tsx'
,然后使用Store
的api
进行操作,但是这样并不会触发react
组件的更新,因为他们之间缺少了映射关系,这时候就需要用到react-redux
这个第三方库
Redux
和react-redux
是不同的库,如果我们想要在react
中使用,我们需要用到react-redux
这个库,主要作用是将我们项目的状态集成到Redux
中去管理需要关注的有:connect, Provider
connect
-
connect
方法,顾名思义,主要将容器组件和redux进行连接
// 这里是把component这个组件进行连接,连接后可在props上查看映射关系
const appContainer = connect(mapStateToProps, mapDispatchToProps)(component)
- 他有两个参数:
mapStateToProps
和mapDispatchToProps
,这两个参数的类型都是函数,具体作用如下: -
mapStateToProps
:将Redux
的state
映射到组件的props
上 -
mapDispatchToProps
:将Redux
的action
映射到组件的props
上,如下:
redux/index.tsx
:import { connect } from 'react-redux'
import appContainer from '../views/Appcontainer'
import ACTION from './action'function mapStateToProps(state: any) {
// 这里将会把 strore 中的initState映射到组件的props上
return {
count: state.count
}
}function mapDispatchToProps(dispatch: (obj: any) => void) {
return {
// CHANGEVALUE, DECREASE, INCREASE这些函数名会映射到被连接的组件props上
CHANGEVALUE: (obj:any) => {
// 当连接redux的组件调用props上的CHANGEVALUE方法时,此处将分发对应的Action,Action在redux/action/index.tsx中维护
// 找到reducers中相匹配的action,然后执行定义的方法
dispatch(ACTION.CHANGEVALUE(obj))
},
DECREASE: () => {
dispatch(ACTION.DECREASE)
},
INCREASE: () => {
dispatch(ACTION.INCREASE)
}
}
}
// 此处将连接好的组件导出
export const AppContainer = connect(mapStateToProps, mapDispatchToProps)(appContainer)
如果需要现在使用导出的Provider 它主要的功能有:appContainer
组件,还需要用到react-redux
提供的Provider
组件
- 在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
- 接收Redux的store作为props,并通过context传递给子组件
App.tsx
import * as React from 'react'
import { Provider } from 'react-redux'
import './App.css'
import { AppContainer } from './redux'
import store from './redux/store'class App extends React.Component {
public render(): JSX.Element {
return ()
}
}export default App
【初探react-redux】
AppContainer.tsx
import * as React from 'react'
import { HashRouter as Router, Route } from 'react-router-dom'
import Nav from '../../component/nav'
import { loadable, route } from '../../routes'
import Home from '../Home'interface IRouteItem {
component: Promise,
path: string
}export default class Appcontainer extends React.Component {
public render ():JSX.Element {
return (
{
route.map((item:IRouteItem, index:number) => {
return (
)
})
}
)
}
}
验证[图片上传失败...(image-aa2163-1530862614905)]react-redux
已经将store
映射到Appcontainer
组件,如下:
可以看到子孙组件调用 在编写组件的时候我们为了可维护性,不会把组件都写在一个文件,所以肯定会有很多子组件或者孙子组件。一般来说,我们最外层的父组件用于逻辑处理,而子组件等用来做UI显示。Appcontainer
组件的props已经有了之前在redux/index.tsx
中定义的方法,现在就可以在Appcontainer
中直接使用这些方法来修改store
但是在子孙组件中,获取
store
不能如同在Appcontainer
组件中一样通过this.props.xx
获取,现在了解的有三种方法:- 1.
Appcontainer
作为父组件,可以通过props
一层一层的把方法和值传递给子组件或者孙子组件 - 2.假设现在有子组件
A
,在redux/index.tsx
使用connect
方法将A
组件与redux
进行连接,再导出调用,这样子组件也有了和Appcontainer
组件一样的操作store
的方法和值 - 3.在
Appcontainer
组件中定义context
上下文,子组件通过this.context.xx.
来获取
context
Appcontainer.tsx
中:
import * as PropTypes from 'prop-types'
import * as React from 'react'interface IRouteItem {
component: Promise,
path: string
}export default class Appcontainer extends React.Component{
// childContextTypes属性,声明给子孙组件提供的属性
public static childContextTypes = {
store: PropTypes.object
}
constructor (props:any) {
super(props)
}
// 这个方法给子组件设置context的值,值为当前组件的props
public getChildContext () {
return {
store: this.props
}
}
public render ():JSX.Element {
return (
...
)
}
}
子组件
Counter
中:import * as PropTypes from 'prop-types'export default class Counter extends React.Component {
// 声明静态属性 contextTypes 才能访问顶层组件定义的context,属性名字也需要和父组件一样,否则访问不到值
public static contextTypes = {
store: PropTypes.object
}
public handleDecreaseCB () {
this.context.store.DECREASE()
}
public render () {
return (
{this.props.children})
}
}
demo效果如下:
![初探react-redux](https://img.it610.com/image/info10/9109b823aa8645ba8689ce9b960b6b14.gif)
文章图片
image
redux
持久化
效果图中有一个问题,就是刷新后,原来的store变为了0,变成之前初始化state
的值,如果需要让数据持久化,则需要用到一个第三方包:redux-persist
,配置也很简单:安装
redux-persist
包
yarn add redux-persist --save
redux/store/index.tsx
import { createStore } from 'redux'
import * as persist from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import reducer from '../reducers'const { persistStore, persistReducer } = persistconst persistConfig = {
key: 'root',
storage,
}
const initState = {
count: 0
}
const persistedReducer = persistReducer(persistConfig, reducer)
const store = createStore(persistedReducer, initState)
const persistor= persistStore(store)export default {
persistor,
store
}
App.tsx
import * as React from 'react'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
import './App.css'
import { AppContainer } from './redux'
import { persistor, store } from './redux/store'export default class App extends React.Component {
public render(): JSX.Element {
return (
)
}
}
以上方法都是参照官方的例子实现,详见:gitHub,效果如下:
![初探react-redux](https://img.it610.com/image/info10/d932906c6edb4864b1884fcadcd49787.gif)
文章图片
image Demo地址
推荐阅读
- 为什么你的路演总会超时()
- 财商智慧课(六)
- 异地恋中,逐渐适应一个人到底意味着什么()
- 做一件事情的基本原理是什么()
- 今天写一些什么
- 眉头开了
- 吃了早餐,反而容易饿(为什么?)
- 我们应该和什么样的人交朋友
- 做个俗物有什么不好
- 为什么越花钱的人越有钱,越舍不得花钱的人却越穷()