好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

从零搭建React+TypeScript的后台项目(三)

本章主要讲解redux在React项目中的应用。 Redux官方文档 。

一、基本概念

Action

action简单理解就是对象字面量。功能上来说就是把数据从应用传到store的有效载荷,和Vue中Mutation提交载荷类似。

有action创造函数,是一个生成action的方法。下面就是一个简单的同步actin:

export  function   setGlobalState(data: {}) {
      return  {type: 'SET_GLOBAL_STATE' , data}
} 

action生成后,store并没有生成或者发生变化,只是说明我要更新store了。怎么更新需要通过reducer函数来处理。

Reducer

reducer本质上是纯函数,接受oldState、action两个参数,返回newState。reducer告诉开发系统是怎么更新store的。

 function   global(state: Global, action: any) {
      switch  (action.type) {
          case  'SET_GLOBAL_STATE' :
              return   action.data
          default  :
              return   InitGlobalState
    }
}

reducer支持组合和拆分,可以根据项目业务合理进行组织。

Store

store就是项目中的数据流,将action和reducer联系起来。Redux应用只有一个store,起职责如下:

维持应用的 state; 提供  getState()  方法获取 state; 提供  dispatch(action)  方法更新 state; 通过  subscribe(listener)  注册监听器; 通过  subscribe(listener)  返回的函数注销监听器。

下面我们初始化一个store

import { createStore } from 'redux'

 //   初始化store 
const Store =  createStore(
  rootReducer,
) 

二、React中使用Redux

 redux是一种状态管理通用实现方案,可以应用在许多地方,并不受库的限制。react-redux正是两者搭配起来实现的通用库。

yarn add react-redux

Provider全局注入store

然后通过react-redux提供的Provider组件实现store注入。

import Store from './store' 
import { Provider } from  'react-redux' 

ReactDOM.render(
     <Provider store={Store}>
        <App/>
    </Provider>,
    document.getElementById('root') as HTMLElement   //  类型断言 
);

这样项目中的所有组件都能访问到store中state,并且通过dispatch来更新state。总之,store在项目中是单独存在的一个整体,作为数据源存在。而项目外部可以获取state,改变store中state的唯一方法就是dispatch(action)。

组件中使用store

下面我们一todo.tsx组件为例,介绍组件中是如何获取、更新state的。

import { connect } from 'react-redux' 

const mapStateToProps  = (state:InitState) =>  {
      return   {
        todos: state.todos
    }
}
  
const mapDispatchToProps  = (dispatch:Dis) =>  {
      return   {
        onAddTodo(value: string) {
            dispatch(addTodo(value))
      }
    }
} 

Provider组件将store注入到组件中的本质,还是将store通过组件的props关联到每个组件上。接下来我们将两个map函数绑定到组件的属性上。

 interface Props {
    todos: []
    onAddTodo:(value: string)  =>  void   
}
interface State {
    value: string
}

class Todo extends React.Component <Props, State>  {    

    constructor(props: Props) {
        super(props)
          this .state =  {
            value:  '' 
        }
    }

    handleAddTodo  = () =>  {
          this .props.onAddTodo( this  .state.value)
          this  .setState({
            value:  '' 
        })
    }

    handleInputChange  = (e: any) =>  {
        const { value }  =  e.target
          this  .setState({
            value
        })
    }

    render () {
          return  (
             <div>
                <Input value={ this .state.value} placeholder="请输入清单项" onChange={ this .handleInputChange}/>
                <Button onClick={ this .handleAddTodo}>添加</Button>
                <ul> 
                    {  this .props.todos.map((todo: any) =>  (
                         <li>{todo.text}</li>
                     ))}
                 </ul>
            </div>
         )
    }
}

export   default   connect(
    mapStateToProps,
    mapDispatchToProps
)(Todo) 

这样我们就实现了在组件内部获取state,并且通过界面交互可以动态新增待办清单,更新store,最后实时渲染页面的功能。

三、redux高级用法

组合拆分reducer

之前有讲到可以拆分reducer,做到单一功能模块对应一个reducer。类似于Vuex中将store分成多个子modules。

redux提供的combineReducers方法即可接受多个reducer。

import { createStore, combineReducers } from 'redux' 
import Todo from  './todo/reducers' 
import Ware from  './ware/reducers' 

const rootReducer  =  combineReducers(
    Object.assign({}, Todo, Ware)
) 

然后将rootReducer传入createStore中即可。

action中间件

中间件MiddleWare可以在我们进行disatch时,更加细粒化的跟踪store的变化,并且允许我们建立异步action。

下面我们来看react-thunk中间件的作用,使用middleWare后,action创建函数除了返回action对象外,还能返回函数。这个函数会被react-thunk执行,在函数内部能执行更多操作,执行异步请求、dispatch action。

yarn add react-thunk

下面我们来修改下store/index.tsx文件:

import thunkMiddleware from 'redux-thunk' 
import { createStore, applyMiddleware, combineReducers } from  'redux' 

const Store  =  createStore(
  rootReducer,
  applyMiddleware(  
    thunkMiddleware,
  )
) 

现在我们的action创造函数中就能像下面这样写:

export  function   addTodo(text: string) {
      return  { type: 'ADD_TODO' , text }
}

export   function   asyncAddTodo(text: string) {
    return  (dispatch:Dis, getState: Get) =>  {
      if   (checkStoreTodo(getState(),text)) {
        //   在 thunk 里 dispatch 另一个 thunk! 
       return   dispatch(addTodo(text))
    }   else   {
        //   告诉调用代码不需要再等待。 
       return   Promise.resolve()
    }
  }
} 

还有react-logger提供的中间件,在本地开发时在进行dispatch时,能打印改动日志。不仅如此,我们还可以自定义middleWare,用来实现自己想要的逻辑效果。

现在redux在react中一些基本用法都介绍完毕了,react中的一些第三方库基本和TypeScript结合的很好,可能有时候回调函数的参数不知道如何进行类型定义。有个d.ts文件则能在开发时进行智能提示,这个文件主要是在ts文件以js文件发布后,用来标记js文件里面对应的类型。

TypeScript官方文档 有兴趣的朋友可以看看。

题外话,redux使用起来有点复杂。安利另外一个状态管理方案 MobX ,并且在react得到很好的实现,真正做到了开箱即用,代码写到哪里就在哪里使用!

这是一个系列文章:

从零搭建React+TypeScript的后台项目(一) --构建基础React+TypeScript项目

从零搭建React+TypeScript的后台项目(二) --后台router实现方案

从零搭建React+TypeScript的后台项目(三) --Redux基本配置 

查看更多关于从零搭建React+TypeScript的后台项目(三)的详细内容...

  阅读:52次