react-redux 基本原理 & 使用redux 处理异步逻辑

Redux 出现的背景

随着对 React 使用的深入,你会发现组件级别的 state,和从上而下传递的 props 这两个状态机制,无法满足复杂功能的需要,例如跨层级之间的组件的数据共享和传递,Redux应运而生。

state应用 & redux应用对比

左图是单个 React 组件,它的状态可以用内部的 state 来维护,而且这个 state 在组件外部是无法访问的。
右图则是使用 Redux 的场景,用全局唯一的 Store 维护了整个应用程序的状态。对于页面的多个组件,都是从这个 Store 中获取状态的,从而保证组件之间能够共享状态。

从这张对比图,我们可以看到 Redux Store 的两个特点:

  • Redux Store 是全局唯一的。即整个应用程序一般只有一个 Store。
  • Redux Store 是树状结构,可以更天然地映射到组件树的结构,虽然不是必须的。

有两个场景可以典型地体现出这些特点:

  • 跨组件的状态共享:当某个组件发起一个请求时,将某个 Loading 的数据状态设为 True,另一个全局状态组件则显示 Loading 的状态。
  • 同组件多个实例的状态共享:某个页面组件初次加载时,会发送请求拿回了一个数据,切换到另外一个页面后又返回,这时数据已经存在,无需重新加载。设想如果是本地的组件 state,那么组件销毁后重新创建,state 也会被重置,就还需要重新获取数据。

Redux的三个基本概念

Redux 主要引入了以下三个概念:

  • State: StateStore,一般就是一个纯 JavaScript Object。
  • Action: 是一个 Object,用于描述发生的动作。
  • Reducer: 是一个函数,接收 ActionState 并作为参数,通过计算得到新的 Store (每次返回一个新的对象)

state & action & reducer之间的关系

所有对于Store的修改都必须通过Reducer去完成,这样一方面能保证数据的不可变性(Immutable),同时也带来了可预测性和易于调试的特点 。

  • 可预测性 - 给定一个初始状态和一系列Action,一定能得到一致的结果。
  • 易于调试 - 基于浏览器插件的开发工具可以跟踪 Store 中数据的变化并进行暂停、回放。

如何在React中使用Redux: react-redux

在实际场景中,Redux Store 中的状态最终一定是会体现在 UI 上的,即通过 React 组件展示给用户。那么如何建立 Redux 和 React 的联系呢?

  • React 组件能够在依赖的 Store 的数据发生变化时,重新 Render;
  • 在 React 组件中,能够在某些时机去 dispatch 一个 action,从而触发 Store 的更新。

Facebook 提供的 react-redux 工具库,作用就是建立一个桥梁,让 React 和 Redux 实现互通。

  • 利用了 React 的 Context 机制去存放 Store 的信息。
import React from 'react'
import ReactDOM from 'react-dom'

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

import App from './App'

const rootElement = document.getElementById('root')
ReactDOM.render(
  
    
  ,
  rootElement
)

Provider 组件作为整个应用程序的根节点,并将 Store 作为属性传给了这个组件,这样所有下层的组件就都能够使用 Redux 了。

在函数组件中使用 Redux 就非常简单了:
利用 react-redux 提供的 useSelectoruseDispatch 这两个 Hooks。

  • useSelector 让一个组件能够在 Store 的某些数据发生变化时重新 render。
  • useDispatch 返回 dispatch,让组件能够 dispatch 一些 action 从而修改Store
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'

export function Counter() {
  // 从 state 中获取当前的计数值
  const count = useSelector(state => state.value)

  // 获得当前 store 的 dispatch 方法
  const dispatch = useDispatch()

  // 在按钮的 click 时间中去分发 action 来修改 store
  return (
    
{count}
) }
react-redux的单向数据流

使用Redux处理异步逻辑

处理异步逻辑也常常被称为异步 Action,它几乎是 React 面试中必问的一道题,可以认为这是 Redux 使用的进阶场景。

只有能够解释清楚异步 Action,才算是真正理解了 Redux

例:异步场景-发送请求获取数据

不推荐:在函数组件中发送请求 - Store 完全作为一个存放数据的地方

function DataList() {
const dispatch = useDispatch();
// 在组件初次加载时发起请求
useEffect(() => {
  // 请求发送时
  dispatch({ type: 'FETCH_DATA_BEGIN' });
  fetch('/some-url').then(res => {
    // 请求成功时
    dispatch({ type: 'FETCH_DATA_SUCCESS', data: res });
  }).catch(err => {
    // 请求失败时
    dispatch({ type: 'FETCH_DATA_FAILURE', error: err });
  })
}, []);

// 绑定到 state 的变化
const data = useSelector(state => state.data);
const pending = useSelector(state => state.pending);
const error = useSelector(state => state.error);

// 根据 state 显示不同的状态
if (error) return 'Error.';
if (pending) return 'Loading...';
return ;
}

很显然,发送请求获取数据并进行错误处理这个逻辑是不可重用的。假设我们希望在另外一个组件中也能发送同样的请求,就不得不将这段代码重新实现一遍。因此,Redux 中提供了 middleware 这样一个机制,让我们可以巧妙地实现所谓异步 Action 的概念。

推荐:使用 middlewate - dispatch 一个函数用于发送请求

  • 在创建 redux store时指定 redux-thunk 中间件
    import { createStore, applyMiddleware } from 'redux'
    import thunkMiddleware from 'redux-thunk'
    import rootReducer from './reducer'
    
    const composedEnhancer = applyMiddleware(thunkMiddleware)
    const store = createStore(rootReducer, composedEnhancer)
    
  • dispatch actiondispatch一个函数
    import fetchData from './fetchData';
    
    function DataList() {
      const dispatch = useDispatch();
      // dispatch 了一个函数由 redux-thunk 中间件去执行
      dispatch(fetchData());
    }
    
  • fetchData定义
    function fetchData() {
      return dispatch => {
        dispatch({ type: 'FETCH_DATA_BEGIN' });
        fetch('/some-url').then(res => {
          dispatch({ type: 'FETCH_DATA_SUCCESS', data: res });
        }).catch(err => {
          dispatch({ type: 'FETCH_DATA_FAILURE', error: err });
        })
      }
    }
    

这一套结合 redux-thunk 中间件的机制,我们就称之为异步 Action。

所以说异步 Action 并不是一个具体的概念,而可以把它看作是 Redux 的一个使用模式。它通过组合使用同步 Action ,在没有引入新概念的同时,用一致的方式提供了处理异步逻辑的方案。

你可能感兴趣的:(react-redux 基本原理 & 使用redux 处理异步逻辑)