React Native Redux Typescript使用

作者: ArthurWang | 来源:发表于2018-07-22 14:06 被阅读8次

    上一篇博客我们用理论和代码实践介绍了 使用redux 发起action 在reducers里生成state 然后重新渲染组件

    Redux 的核心理念是严格的单向数据流,只能通过 dispatch(action) 的方式修改 store,流程如下:

    view ->  action -> reducer -> store
    

    但是在业务复杂的以及和api数据对接的过程中肯定会遇到大量的异步操作。我们如何来解决这些场景呢?

    redux中间件

    什么是redux中间件

    redux中间件
    这里我们先从redux的中间件说起, 中间件,顾名思义:进行中间处理的物件。类似于面向对象编程的AOP编程思想(不了解AOP的可以忽略这句话)
    简单的说:中间件可以控制在store dispatch action之前和之后的业务逻辑。也就是说 中间件实现了改写 store.dispatch 方法实现了action -> reducer的拦截的行为。
    如果我们分别注册三个中间件: 中间件A 中间件B 中间件C
    那么

    中间件A -> 中间件B-> 中间件C-> 原始 dispatch -> 中间件C -> 中间件B -> 中间件A
    

    和异步处理的关系

    综上所述:中间件可以领过的改变 dispatch的时机,这样我们就可以很方便的处理异步场景了。
    因此各种 redux异步处理中间件应运而生。比较知名的有redux-thunkredux-saga

    redux-thunk

    redux-thunk中间件可以让action创建函数先不返回一个action对象,而是返回一个函数,函数传递两个参数(dispatch,getState),在函数体内进行业务逻辑的封装

    function add() {
        return {
            type: 'ADD',
        }
    }
    
    function addIfOdd() {
        return (dispatch, getState) => {
            const currentValue = getState();
            if (currentValue % 2 == 0) {
                return false;
            }
            //分发一个任务
            dispatch(add())
        }
    }
    

    详细代码可以查看分支:https://github.com/YahuiWong/react-native-typescript/tree/redux-thunk

    redux-saga

    sages 采用 Generator 函数来 yield Effects(包含指令的文本对象)。Generator 函数的作用是可以暂停执行,再次执行的时候从上次暂停的地方继续执行。Effect 是一个简单的对象,该对象包含了一些给 middleware 解释执行的信息。你可以通过使用 effects API 如 fork,call,take,put,cancel 等来创建 Effect。( redux-saga API 参考)

    如 yield call(fetch, '/products') 即 yield 了下面的对象,call 创建了一条描述结果的信息,然后,redux-saga middleware 将确保执行这些指令并将指令的结果返回给 Generator:

    // Effect -> 调用 fetch 函数并传递 `./products` 作为参数
    {
      type: CALL,
      function: fetch,
      args: ['./products']
    }
    

    与 redux-thunk 不同的是,在 redux-saga 中,UI 组件自身从来不会触发任务,它们总是会 dispatch 一个 action 来通知在 UI 中哪些地方发生了改变,而不需要对 action 进行修改。redux-saga 将异步任务进行了集中处理,且方便测试。

    dispacth({ type: 'FETCH_REQUEST', url: /* ... */} );
    所有的东西都必须被封装在 sagas 中。sagas 包含3个部分,用于联合执行任务:

    worker saga
    做所有的工作,如调用 API,进行异步请求,并且获得返回结果
    watcher saga
    监听被 dispatch 的 actions,当接收到 action 或者知道其被触发时,调用 worker saga 执行任务
    root saga
    立即启动 sagas 的唯一入口
    

    ☀ 如何使用?
    首先,我们得在文件入口中加入 saga 中间件,并且启动它,它会一直运行:

    //...
    import { createStore, applyMiddleware} from 'redux';
    import createSagaMiddleware from 'redux-saga';
    import appReducer from './reducers';
    import rootSaga from './saga';
    //...
    
    const sagaMiddleware = createSagaMiddleware()
    
    const store=createStore(rootReducer,applyMiddleware(sagaMiddleware));
    
    sagaMiddleware.run(rootSaga)
    
    render(
        <Provider store={store}>
            <App />
        </Provider>,
        document.getElementById('app')
    );
    

    然后,就可以在 sagas 文件夹中集中写 saga 文件了:

    import {delay} from 'redux-saga';
    import {put,takeEvery,all} from 'redux-saga/effects';
    import {ADD} from './actionsTypes';
    function* addSync(){
        yield delay(1000);
        yield put({type:ADD})
    }
    function* watchaddSync(){
    yield takeEvery("addSync",addSync)
    }
    
    export default function* rootSaga(){
        yield all([
            watchaddSync()
        ])
    }
    

    在 redux-saga 中的基本概念就是:sagas 自身不真正执行副作用(如函数 call),但是会构造一个需要执行作用的描述。中间件会执行该副作用并把结果返回给 generator 函数。

    对上述例子的说明:

    (1)引入的 redux-saga/effects 都是纯函数,每个函数构造一个特殊的对象,其中包含着中间件需要执行的指令,如:call(fetchUrl, url) 返回一个类似于 {type: CALL, function: fetchUrl, args: [url]} 的对象。

    (2)在 watcher saga watchFetchRequests中:

    首先 yield take('FETCH_REQUEST') 来告诉中间件我们正在等待一个类型为 FETCH_REQUEST 的 action,然后中间件会暂停执行 wacthFetchRequests generator 函数,直到 FETCH_REQUEST action 被 dispatch。一旦我们获得了匹配的 action,中间件就会恢复执行 generator 函数。

    下一条指令 fork(fetchUrl, action.url) 告诉中间件去无阻塞调用一个新的 fetchUrl 任务,action.url 作为 fetchUrl 函数的参数传递。中间件会触发 fetchUrl generator 并且不会阻塞 watchFetchRequests。当fetchUrl 开始执行的时候,watchFetchRequests 会继续监听其它的 watchFetchRequests actions。当然,JavaScript 是单线程的,redux-saga 让事情看起来是同时进行的。

    (3)在 worker saga fetchUrl 中,call(fetch,url) 指示中间件去调用 fetch 函数,同时,会阻塞fetchUrl 的执行,中间件会停止 generator 函数,直到 fetch 返回的 Promise 被 resolved(或 rejected),然后才恢复执行 generator 函数。

    最后,总结一下 redux-saga 的优点:

    (1)声明式 Effects:所有的操作以JavaScript对象的方式被 yield,并被 middleware 执行。使得在 saga 内部测试变得更加容易,可以通过简单地遍历 Generator 并在 yield 后的成功值上面做一个 deepEqual 测试。
    (2)高级的异步控制流以及并发管理:可以使用简单的同步方式描述异步流,并通过 fork 实现并发任务。
    (3)架构上的优势:将所有的异步流程控制都移入到了 sagas,UI 组件不用执行业务逻辑,只需 dispatch action 就行,增强组件复用性。

    详细代码可以查看分支:https://github.com/YahuiWong/react-native-typescript/tree/redux-saga 如果觉得有用,请Star ,谢谢!

    参考:
    https://segmentfault.com/a/1190000007248878#articleHeader7

    相关文章

      网友评论

        本文标题:React Native Redux Typescript使用

        本文链接:https://www.haomeiwen.com/subject/dwvlmftx.html