likes
comments
collection
share

react-redux

作者站长头像
站长
· 阅读数 26

开始使用 React Redux

React Redux 是 Redux 的官方 React UI 绑定层。它允许 React 组件从 Redux 存储中读取数据,并将操作调度到存储以更新状态。

Let’s Learn Modern Redux! (with Mark Erikson) — Learn With Jason - YouTube

Redux in 2023: What you need to know - YouTube

为什么使用react-redux

这是React的官方Redux UI绑定

虽然Redux可以与任何UI层一起使用,但它最初是为与React一起使用而设计的。许多其他框架都有UI绑定层,但React Redux由Redux团队直接维护。作为React的官方Redux绑定,React Redux可以随时更新两个库中的任何API更改,以确保您的React组件按预期运行。它的预期用途采用了React的设计原则——编写声明性组件。

性能优化

React通常很快,但默认情况下,对组件的任何更新都会导致React重新渲染组件树中该部分内的所有组件。这确实需要工作,如果给定组件的数据没有改变,那么重新渲染可能会浪费一些精力,因为请求的UI输出是相同的。

如果性能是一个问题,那么提高性能的最佳方法是跳过不必要的重新渲染,这样组件只有在其数据实际发生更改时才能重新渲染。React Redux在内部实现了许多性能优化,因此您自己的组件只有在实际需要时才会重新渲染。

此外,通过连接React组件树中的多个组件,可以确保每个连接的组件只从存储状态中提取该组件所需的特定数据。这意味着您自己的组件将不太频繁地重新渲染,因为大多数时候这些特定的数据片段没有改变。

社区支持

作为React和Redux的官方绑定库,React Redux拥有庞大的用户群体。这使得寻求帮助、了解最佳实践、使用基于React Redux构建的库以及在不同的应用程序中重用您的知识变得更加容易。

connect

  1. mapStateToProps: 这是一个可选参数,用于将 Redux store 中的状态映射到组件的 props 上。
  2. mapDispatchToProps: 这也是一个可选参数,用于创建在调用时派发 actions 的函数,并将这些函数作为 props 传递给组件。
  3. mergeProps: 这是另一个可选参数,用于控制 mapStateToProps 和 mapDispatchToProps 的合并方式。它允许你自定义最终传递给组件的 props。
  4. options: 最后一个参数也是可选的,用于配置 connect 函数的行为。常见的选项包括 pureareStatesEqual,用于控制组件是否进行浅比较以及在什么情况下重新计算状态 基本使用:
export default connect(mapStateToProps,mapDispatchToProps,mergeProps,options)(TodoList)

mapStateToProps

作为传递给 connect 的第一个参数,mapStateToProps 用于选择连接的组件需要从 store 中获取的数据。通常简称为 mapState

  • 每当 store 的状态发生变化时,mapStateToProps 将被调用。
  • 它接收整个 store 的状态,并应该返回一个包含该组件所需数据的对象。

mapStateToProps 需要定义为一个函数,可以使用函数声明或者箭头函数。这个函数应该作为 connect 的第一个参数传递,并且在 Redux store 状态发生变化时会被调用。如果你不希望订阅 store,可以在 connect 中传递 null 或 undefined 替代 mapStateToProps。

function mapStateToProps(state, ownProps?)

参数:

  1. state(必传)
  2. ownProps(可选)

state:

mapStateToProps 函数的第一个参数是整个 Redux store 的状态(与调用 store.getState() 返回的值相同)。因此,第一个参数传统上被称为 state。(虽然你可以为参数取任何你想要的名称,但称其为 store 是不正确的——它是"状态值",而不是"store 实例"。) ownProps:

如果你的组件需要使用自己的 props 从 store 中检索数据,你可以定义这个函数的第二个参数 ownProps。这个参数将包含由 connect 生成的包装组件传递的所有 props。

function mapStateToProps(state, ownProps) {  
    const { visibilityFilter } = state  
    // ownProps would look like { "id" : 123 }  
    const { id } = ownProps  
    const todo = getTodoById(state, id)  

    // component receives additionally:  
    return { todo, visibilityFilter }  
}

返回值:

mapStateToProps 函数应该返回一个包含组件所需数据的普通对象:

  • 对象中的每个字段将成为你实际组件的 prop
  • 字段中的值将用于确定组件是否需要重新渲染
注意:在需要对渲染性能进行更多控制的高级场景中,mapStateToProps也可以返回一个函数。
在这种情况下,该函数将用作特定组件实例的最终mapStateToProps。这允许您执行每个实例的记忆。
有关更多详细信息,请参阅文档的高级用法:工厂功能部分,以及PR#279及其添加的测试。
大多数应用程序从不需要此功能。

mapStateToProps函数可以重新塑造自己的数据

mapStateToProps 函数不仅仅可以返回当前组件需要的store中的数据。还可以把store中的数据进行重新组合成新的数据。

举个例子,假设我们有一个 Redux store,其中存储了用户的信息和订单的信息

const initialState = {
  user: {
    name: 'John Doe',
    age: 30,
    email: 'john@example.com',
  },
  orders: [
    { id: 1, product: 'Item A', amount: 100 },
    { id: 2, product: 'Item B', amount: 50 },
  ],
};

在组件中,我们可能只需要用户的名称和订单的总金额,而不需要用户的完整信息和订单的详细列表。这时,我们可以在 mapStateToProps 中进行重新塑造,只返回需要的数据:

import { connect } from 'react-redux';

const MyComponent = ({ userName, totalOrderAmount }) => {
  // 使用重新塑造后的数据 userName 和 totalOrderAmount
  // ...
};

const mapStateToProps = (state) => {
  const { name, orders } = state.user;
  const totalOrderAmount = orders.reduce((total, order) => total + order.amount, 0);

  return {
    userName: name,
    totalOrderAmount,
  };
};

export default connect(mapStateToProps)(MyComponent);

mapStateToProps 函数应该尽量保持简单和高效

原因有几点:

  1. 实时调用:mapStateToProps 在每次 Redux store 的状态发生变化时都会被调用,因此它应该具有高效的性能,以确保在频繁的状态更新情况下不会影响应用的性能。
  2. 数据获取:mapStateToProps 主要用于从 Redux store 中提取数据,并将其映射到组件的 props 上。如果在这个函数中执行复杂的逻辑处理,可能会导致获取数据的速度变慢,影响组件的渲染性能。
  3. 数据共享:在大型应用中,多个组件可能会共享相同的 mapStateToProps 函数,如果该函数过于复杂,可能会导致多个组件都受到性能影响。

为了保持 mapStateToProps 函数的高效性,推荐遵循以下几个指导原则:

  1. 数据规范化:尽量将 Redux store 中的数据进行规范化,避免在 mapStateToProps 中进行复杂的数据处理和转换。
  2. 数据过滤:只返回组件所需的数据,避免返回不必要的数据,以减少不必要的渲染和计算开销。
  3. Memoization:如果 mapStateToProps 中的数据计算较为复杂且不经常变化,可以使用 memoization 技术,缓存计算结果,以减少重复计算。
  4. 使用 Reselect:对于复杂的数据处理和转换逻辑,可以考虑使用 Reselect 库,它提供了高效的选择器(selector)功能,可以优化数据的获取和处理。

mapStateToProps应该是纯函数和同步的

就像 Redux 的 reducer 一样,mapStateToProps 函数应该始终是 100% 纯净和同步的。它只应该接收 state(和 ownProps,如果需要)作为参数,并且在不改变这些参数的情况下,将组件所需的数据返回为 props。它不应该用于触发异步行为,比如用于数据获取的 AJAX 调用,并且这些函数不应该声明为 async。

mapStateToProps的返回值决定了当前组件是否重新渲染

React Redux 在内部实现了 shouldComponentUpdate 方法,确保当你的组件所需的数据发生变化时,包装组件会精确地重新渲染。默认情况下,React Redux 使用 === 比较(即"浅相等"检查)来判断从 mapStateToProps 返回的对象是否不同,它会对返回对象的每个字段进行比较。如果任何字段发生了变化,那么你的组件将会重新渲染,以便能够接收到更新后的 prop 值。请注意,返回一个被修改过的相同引用的对象是一个常见的错误,这可能导致你的组件没有按预期重新渲染。

组件重新渲染的情况:

(state) => stateProps(state, ownProps) => stateProps
mapStateToProps 运行时机当 store 的 state 改变时,stateProps传给组件当 store 的 state 改变时或者 ownProps 的任何字段有变化 ,stateProps传给组件
组件重新渲染时机stateProps 的任何字段有变化时stateProps 的任何字段有变化或者 ownProps 的任何字段有变化时
### mapDispatchToProps
作为传递给 connect 的第二个参数,mapDispatchToProps 用于向 store 发送 action。

dispatch 是 Redux store 的一个函数。你可以调用 store.dispatch 来发送一个 action。这是触发状态变化的唯一方式。

使用 React Redux,你的组件不会直接访问 store --- connect 会替你处理。React Redux 提供了两种方式让组件派发 actions:

  1. 默认情况下,连接的组件会接收到 props.dispatch,并且可以自己dispatch actions。

function Counter({ count, dispatch }) {
  return (
    <div>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button>
      <span>{count}</span>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
      <button onClick={() => dispatch({ type: 'RESET' })}>reset</button>
    </div>
  )
}

connect(mapStateToProps /** no second argument */)(MyComponent)
  1. connect 函数可以接受一个名为 mapDispatchToProps 的参数,它允许你创建在调用时dispatch actions 的函数,并将这些函数作为 props 传递给你的组件。

参数:

  1. dispatch

mapDispatchToProps 函数将以 dispatch 作为第一个参数进行调用。通常你会利用这个特性,通过返回新的函数,在这些函数内部调用 dispatch(),然后要么直接传递一个普通的 action 对象,要么传递一个 action 创建函数的结果。这样可以方便地派发 Redux actions。

  1. ownProps (可选)

如果你的 mapDispatchToProps 函数声明接受两个参数,它将以 dispatch 作为第一个参数,以传递给连接组件的 props 作为第二个参数进行调用,并且在连接组件接收到新的 props 时会重新调用该函数。

这意味着,与其在组件重新渲染时重新绑定新的 props 到 action dispatchers,你可以在组件的 props 改变时这样做。也就是说,在组件接收到新的 props 时,mapDispatchToProps 会重新执行,从而在需要时为组件重新绑定 action dispatchers。这样做可以更加灵活地处理组件的 props 变化,确保 action dispatchers 能够正确地与组件的 props 关联。

返回值:

mapDispatchToProps 函数应该返回一个普通对象:

  • 对象中的每个字段将成为你自己组件的一个单独的 prop,其值通常应该是一个在调用时派发 action 的函数。
  • 如果在 dispatch 中使用 action 创建函数(而不是纯对象的 actions),有一个约定是将字段键的名称与 action 创建函数的名称相同:
const increment = () => ({ type: 'INCREMENT' })
const decrement = () => ({ type: 'DECREMENT' })
const reset = () => ({ type: 'RESET' })

const mapDispatchToProps = (dispatch) => {
  return {
    // dispatching actions returned by action creators
    increment: () => dispatch(increment()),
    decrement: () => dispatch(decrement()),
    reset: () => dispatch(reset()),
  }
}
// 组件中使用
function Counter({ count, increment, decrement, reset }) {
  return (
    <div>
      <button onClick={decrement}>-</button>
      <span>{count}</span>
      <button onClick={increment}>+</button>
      <button onClick={reset}>reset</button>
    </div>
  )
}

结合bindActionCreators来使用

bindActionCreators 是 Redux 提供的一个辅助函数,用于简化派发 action 的过程。它的主要作用是将 action 创建函数与 dispatch 方法绑定起来,从而使得在组件中直接调用这些 action 创建函数就能自动派发对应的 action,无需手动调用 dispatch

import { bindActionCreators } from 'redux';

// action 创建函数 1
function increment() {
  return { type: 'INCREMENT' };
}

// action 创建函数 2
function decrement() {
  return { type: 'DECREMENT' };
}



// 使用 bindActionCreators 将 action 创建函数绑定到 dispatch 上
const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({ increment, decrement }, dispatch);
};

这样,在组件中就可以直接调用这些绑定后的函数,从而自动派发相应的 action:

// 在组件中调用绑定后的函数,会自动派发对应的 action
this.props.increment(); // 派发 INCREMENT action
this.props.decrement(); // 派发 DECREMENT action

为什么找不到dispatch

TypeError: this.props.dispatch is not a function

只有在以下情况下,才会向组件注入dispatch:

  1. connect函数没有提供mapDispatchToProps函数
// component receives `dispatch`  
connect(mapStateToProps /** no second argument*/)(Component)
  1. 使用mapDispatchToProps时,返回的对象添加了dispatch
const mapDispatchToProps = (dispatch) => {
  return {
    increment: () => dispatch(increment()),
    decrement: () => dispatch(decrement()),
    reset: () => dispatch(reset()),
    dispatch,
  }
}

我可以只使用mapDispatchToProps

你可以通过传递 undefined 或 null 来跳过第一个参数。这样你的组件将不会订阅 Redux store,但仍然可以接收由 mapDispatchToProps 定义的 dispatch props。

connect(null, mapDispatchToProps)(MyComponent)

我可以调用 store.dispatch吗?

在 React 组件中直接与 Redux store 进行交互是一种反模式,无论是通过显式导入 store 还是通过上下文 (参考 Redux FAQ 中有关 store 设置的条目以获取更多详细信息)。让 React Redux 的 connect 处理对 store 的访问,并使用它传递给 props 的 dispatch 来派发 actions。这样能够更好地遵循 Redux 的设计思想,将组件与 Redux store 解耦,使代码更加清晰和可维护。

mergeProps

mergeProps 参数是 connect 函数的一个可选参数。用于控制最终传递给组件的 props 的合并方式。它允许你自定义如何将来自 mapStateToPropsmapDispatchToProps 和组件自身的 props 合并成最终的 props。

默认情况下,mergeProps 参数为 null,这意味着 connect 会使用默认的合并方式来处理这些 props。默认的合并方式是将 mapStateToPropsmapDispatchToProps 和组件自身的 props 作为对象合并,其中优先级依次是 mapDispatchToProps > mapStateToProps > 组件自身的 props。如果有相同的 prop 名称,后面的 props 会覆盖前面的。

但有时候,你可能需要更加细致地控制最终的 props 合并方式,以适应特定的业务需求。这时,你可以传递一个自定义的 mergeProps 函数给 connect,它接收三个参数:statePropsdispatchPropsownPropsstateProps 是来自 mapStateToProps 的 props,dispatchProps 是来自 mapDispatchToProps 的 props,而 ownProps 是组件自身的 props

自定义的 mergeProps 函数应该返回一个新的对象,表示最终的 props。你可以在这个函数中合并、过滤或者对 props 做任何你需要的处理,以确保组件接收到合适的数据和行为。

options

options 参数是用来配置连接过程的选项。这个参数是一个可选对象,可以用来定制 connect 函数的行为。常见的 options 参数包括以下几个选项:

  1. pure(默认为 true)(最新版已经移除):这个选项控制组件是否进行浅比较(shallow compare)。如果设置为 true,那么组件将会在 mapStateToPropsmapDispatchToProps 返回的数据发生变化时重新渲染。如果设置为 false,则组件将总是重新渲染,无论数据是否发生变化。默认情况下,这个选项是开启的,以提高性能。
  2. areStatesEqual:这个选项允许你提供一个自定义的函数,用于判断 Redux store 中的状态是否相等。如果不提供这个选项,connect 默认使用浅比较来判断状态是否发生变化。
  3. areOwnPropsEqual:这个选项允许你提供一个自定义的函数,用于判断组件的 ownProps 是否相等。ownProps 是组件自身的 props,而不是由 mapStateToPropsmapDispatchToProps 传递的 props。
  4. areStatePropsEqual:这个选项允许你提供一个自定义的函数,用于判断 mapStateToProps 返回的 props 是否相等。
  5. areMergedPropsEqual:这个选项允许你提供一个自定义的函数,用于判断 mergeProps 函数合并后的 props 是否相等。

通过配置 options 参数,你可以进一步优化 connect 函数的行为,以满足特定的性能需求或定制化要求。但对于大多数情况,使用默认的选项已经足够满足大部分应用的需求。

API概述

Provider

React Redux 包含一个 组件,Provider 是一个高阶组件(Higher-Order Component),用于将 Redux 的 store 注入整个 React 应用程序中的组件层级。

  1. 提供 Redux 的 store:Provider 组件接受 Redux 的 store 作为 prop,并将其传递给组件树中的所有后代组件。这样,所有的后代组件都可以通过 React 的 "context" 特性访问到 Redux 的 store。
  2. 实现组件与 Redux 的连接:通过将 Redux 的 store 注入到组件树中,Provider 组件实现了组件与 Redux 的连接。这样,组件可以使用 connect 函数(或 React Hooks)来访问 Redux 的状态并将其与组件进行绑定,从而实现了组件的状态管理。
  3. 自动进行状态更新:当 Redux 的 store 发生变化时,Provider 组件会自动重新渲染其后代组件。这样,通过 connect 函数连接的组件会接收到最新的状态,并在需要时更新其界面,从而保持了组件与 Redux 状态的同步。
import React from 'react'  
import ReactDOM from 'react-dom/client'  
  
import { Provider } from 'react-redux'  
import store from './store'  
  
import App from './App'  
  
// As of React 18  
const root = ReactDOM.createRoot(document.getElementById('root'))  
root.render(  
<Provider store={store}>  
<App />  
</Provider>  
)

useSelector

用于在函数式组件中选择和访问 Redux 的状态(state)。

  1. 选择 Redux 的状态:通过 useSelector,你可以选择 Redux 的状态树中的特定部分,即你所关心的状态。你可以传入一个选择器函数作为参数,这个选择器函数接收整个状态树,并返回所需的状态。
  2. 订阅状态的变化:useSelector 在组件中订阅了所选择的状态的变化。当 Redux 的状态发生变化时,与之相关的组件将自动重新渲染,以反映最新的状态。这意味着你无需手动监听状态的变化或编写繁琐的订阅/取消订阅逻辑。
  3. 简化状态访问:使用 useSelector 可以更方便地访问和使用 Redux 的状态。你可以在组件中直接使用选择器函数返回的状态,无需手动获取状态并进行处理。
import { useSelector } from 'react-redux';

function MyComponent() {
  const counter = useSelector(state => state.counter);

  // 使用选择器返回的状态进行组件逻辑处理
  // ...

  return <div>{counter}</div>;
}

useDispatch

用于在函数式组件中获取 Redux 的 dispatch 函数。

  1. 获取 dispatch 函数:通过 useDispatch,你可以直接获取 Redux 的 dispatch 函数,而无需通过连接(connect)或其他方式来访问。
  2. 触发 Redux 的动作:使用 useDispatch 可以直接调用 dispatch 函数来触发 Redux 的动作(actions)。你可以将动作创建函数(action creators)或纯粹的动作对象(plain action objects)传递给 dispatch 函数,从而触发相应的动作。
  3. 简化动作的调用:使用 useDispatch 可以简化调用 Redux 动作的过程。通常,你需要手动调用 dispatch 并传递动作对象。而使用 useDispatch 后,你可以直接调用 dispatch 函数,它会自动触发对应的动作。
import { useDispatch } from 'react-redux';
import { incrementCounter } from './actions';

function MyComponent() {
  const dispatch = useDispatch();

  const handleIncrement = () => {
    dispatch(incrementCounter());
  };

  // 使用 dispatch 触发其他动作
  // ...

  return (
    <div>
      <button onClick={handleIncrement}>Increment</button>
    </div>
  );
}

总结起来,useDispatch 是 React-Redux 提供的一个自定义 Hook,用于在函数式组件中获取 Redux 的 dispatch 函数。它简化了动作的调用过程,允许你直接使用 dispatch 函数来触发 Redux 的动作,并在组件中处理相关的逻辑。

useStore

这个 Hook 返回整个 Redux store 的引用。你可以使用它来访问 Redux store 的状态和方法。

import React from 'react'
import { useStore } from 'react-redux'

export const ExampleComponent = ({ value }) => {
  const store = useStore()

  const onClick = () => {
    // Not _recommended_, but safe
    // This avoids subscribing to the state via `useSelector`
    // Prefer moving this logic into a thunk instead
    const numTodos = store.getState().todos.length
  }

  // EXAMPLE ONLY! Do not do this in a real app.
  // The component will not automatically update if the store state changes
  return <div>{store.getState().todos.length}</div>
}

batch

batch 是一个用来优化组件渲染的函数。它的作用是将多个状态更新操作合并为一次更新,从而减少组件的重新渲染次数,提高性能。

如果你用的是React 18 ,你不需要使用batch. React 18自动对所有状态更新进行合并处理。

import { batch } from 'react-redux';

batch(() => {
  // 多个状态更新操作
  dispatch(action1());
  dispatch(action2());
  // ...
});

react-redux源码

GitHub地址

该项目使用了rollup,我们可以从rollup的配置文件找到项目的入口

react-redux

index.ts

虽然入口文件是index.ts,但主要向外暴露的内容都在exports.ts


import { useSyncExternalStore } from 'use-sync-external-store/shim'
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector'

import { unstable_batchedUpdates as batch } from './utils/reactBatchedUpdates'
import { setBatch } from './utils/batch'

import { initializeUseSelector } from './hooks/useSelector'
import { initializeConnect } from './components/connect'

initializeUseSelector(useSyncExternalStoreWithSelector)
initializeConnect(useSyncExternalStore)

// Enable batched updates in our subscriptions for use
// with standard React renderers (ReactDOM, React Native)
setBatch(batch)

export { batch }

export * from './exports'

exports.ts

import Provider from './components/Provider'
import type { ProviderProps } from './components/Provider'
import connect from './components/connect'
import type {
  Connect,
  ConnectProps,
  ConnectedProps,
} from './components/connect'
import type {
  SelectorFactory,
  Selector,
  MapStateToProps,
  MapStateToPropsFactory,
  MapStateToPropsParam,
  MapDispatchToPropsFunction,
  MapDispatchToProps,
  MapDispatchToPropsFactory,
  MapDispatchToPropsParam,
  MapDispatchToPropsNonObject,
  MergeProps,
} from './connect/selectorFactory'
import { ReactReduxContext } from './components/Context'
import type { ReactReduxContextValue } from './components/Context'

import { useDispatch, createDispatchHook } from './hooks/useDispatch'
import { useSelector, createSelectorHook } from './hooks/useSelector'
import { useStore, createStoreHook } from './hooks/useStore'

import shallowEqual from './utils/shallowEqual'
import type { Subscription } from './utils/Subscription'

export * from './types'
export type {
  ProviderProps,
  SelectorFactory,
  Selector,
  MapStateToProps,
  MapStateToPropsFactory,
  MapStateToPropsParam,
  Connect,
  ConnectProps,
  ConnectedProps,
  MapDispatchToPropsFunction,
  MapDispatchToProps,
  MapDispatchToPropsFactory,
  MapDispatchToPropsParam,
  MapDispatchToPropsNonObject,
  MergeProps,
  ReactReduxContextValue,
  Subscription,
}
export {
  Provider,
  ReactReduxContext,
  connect,
  useDispatch,
  createDispatchHook,
  useSelector,
  createSelectorHook,
  useStore,
  createStoreHook,
  shallowEqual,
}

connect

从 exports 暴露出的 connect 方法,找到connect文件。

函数签名和形参类型

function connect<
  TStateProps = {},
  TDispatchProps = {},
  TOwnProps = {},
  TMergedProps = {},
  State = unknown
>(
  mapStateToProps?: MapStateToPropsParam<TStateProps, TOwnProps, State>,
  mapDispatchToProps?: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
  mergeProps?: MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>,
  {
    // The `pure` option has been removed, so TS doesn't like us destructuring this to check its existence.
    // @ts-ignore
    pure,
    areStatesEqual = strictEqual,
    areOwnPropsEqual = shallowEqual,
    areStatePropsEqual = shallowEqual,
    areMergedPropsEqual = shallowEqual,

    // use React's forwardRef to expose a ref of the wrapped component
    forwardRef = false,

    // the context consumer to use
    context = ReactReduxContext,
  }: ConnectOptions<unknown, unknown, unknown, unknown> = {}
): unknown {//具体内容}

函数签名包含了几个泛型参数和多个可选参数 这是 React Redux 中的 connect 函数的 TypeScript 类型定义。connect 函数用于将 Redux store 和 React 组件连接起来,将 Redux 的状态和动作(actions)映射为组件的 props,使得组件能够访问 Redux store 中的数据并且能够派发 Redux actions。

函数签名包含了几个泛型参数和多个可选参数,下面对每个参数进行解释:

  1. TStateProps:用于指定映射到组件的 Redux 状态(state)的类型,默认为空对象 {}
  2. TDispatchProps:用于指定映射到组件的 Redux 动作(actions)的类型,默认为空对象 {}
  3. TOwnProps:用于指定组件自身的 props 的类型,默认为空对象 {}
  4. TMergedProps:用于指定合并后的 props 的类型,默认为空对象 {}。这里的合并指的是将来自 Redux 状态和 Redux 动作的 props 合并到组件自身的 props 中。
  5. State:用于指定整个 Redux store 的类型,默认为 unknown

可选参数:

  1. mapStateToProps:用于将 Redux store 中的状态映射为组件的 props 的函数。
  2. mapDispatchToProps:用于将 Redux 动作映射为组件的 props 的函数。
  3. mergeProps:用于合并 mapStateToProps 和 mapDispatchToProps 映射的 props 的函数。
  4. option配置对象:
    1. pure:已经移除,不再需要。
    2. areStatesEqual:用于检查 Redux store 的状态是否相等的函数,默认是 strictEqual,用于浅层比较。
    3. areOwnPropsEqual:用于检查组件自身的 props 是否相等的函数,默认是 shallowEqual,用于浅层比较。
    4. areStatePropsEqual:用于检查 mapStateToProps 映射的 props 是否相等的函数,默认是 shallowEqual,用于浅层比较。
    5. areMergedPropsEqual:用于检查合并后的 props 是否相等的函数,默认是 shallowEqual,用于浅层比较。
    6. forwardRef:用于指定是否使用 React 的 forwardRef 来暴露包装后组件的 ref,默认为 false,表示不使用 forwardRef
    7. context:用于指定要使用的 React context 的 consumer,默认为 ReactReduxContext,即 React Redux 提供的上下文。

方法具体内容

通过react的createContext方法,创建新的上下文对象,来接受connect方法中的数据。

function getContext() {
  let realContext = gT[ContextKey]
  if (!realContext) {
    realContext = createContext<ReactReduxContextValue>(null as any)
    if (process.env.NODE_ENV !== 'production') {
      realContext.displayName = 'ReactRedux'
    }
    gT[ContextKey] = realContext
  }
  return realContext
}

在ConnectFunction中处理context数据

react-redux 把处理好的props绑定到组件上,使用了hoist-non-react-statics里的方法hoistStatics。

它的主要功能是将非 React 静态方法从一个组件复制到另一个组件。

import hoistStatics from 'hoist-non-react-statics'

hoistStatics(Connect, WrappedComponent)
转载自:https://juejin.cn/post/7257411422135746619
评论
请登录