@air/react-memoized-context

中文文档
1.0.2发布于 2025/03/04MITTypeScriptESM + CJS近 30 天下载 2.8万
  • 使用您的 React 上下文而不附加在消费者中的重报 - 从上下文“ 飞上” 读取值的能力 - 在回调中有用, 这样您无需将 UI 绑定到上下文值变化中, 只是为了使用回调值 - Redux- l
中文使用文档
文档目录7 节
  1. * 特性
  2. 关于
  3. 何以不反应背景?
  4. 为什么Redux不呢?
  5. 安装
  6. 使用量
  7. 密码框

反应被修改的背景

用类似 Redux 的性能和模式反应上下文而不安装 Redux .

size size

* 特性

  • 使用您的 React 上下文而不在消费者中附加重接
  • 从上下文“ 在飞行上” 读取值的能力 - 在回调中有用, 这样您无需将 UI 绑定在一个上下文值变化中, 只是为了在回调中使用该值
  • 类似 Redux 的模式( 减小、 动作和选择器)
  • 以类型脚本所建

关于

在这里 空运我们需要一个方法来储存 多个 复杂全局状态的实例( React Context API 做什么),但与 Redux 的性能配合. react-memoized-context 解决了这个问题.

何以不反应背景?

反应上下文提供者 全部 每次是消费者 value 修改 - 即使组件没有在 value (若为物. 这会造成很多的表演问题 社区是 尝试 改为 解开我们研究了这些其他的解决方案,但它们要么还没有准备好,要么有太多的虫子,要么缺乏特征(比如在苍蝇上读取值),所以我们决定自己滚动.

为什么Redux不呢?

Redux 作为全局存储器, 当多个组件想要读取和写入到一个 单人 集中值。 但当你想要 多个 具有相同结构的全局值, Redux 并不那么灵活,因为您需要复制您的还原器、 动作和选择器。 反应上下文是不错的 因为你可以绕着另一个提供商.

安装

npm install --save @air/react-memoized-context
yarn add @air/react-memoized-context

使用量

  1. 为上下文创建类型 :

    • 为要存储的值创建类型 :
      export interface User {
        id: string;
        name: string;
        score: number;
      }
      
      export interface UsersTeamContextValue {
        users: User[];
      }
      
    • 创建要更新值的行动类型 :
      export interface UsersTeamContextActions {
        addUser: (user: User) => void;
        assignScore: (userId: User['id'], score: number) => void;
      }
      
    • 为上下文创建类型 - 记得要扩展 MemoizedContextType数字 :
      export interface UsersTeamContextType extends MemoizedContextType<UsersTeamContextValue>, UsersTeamContextActionsType {}
      
    • 为上下文创建默认值 :
      export const defaultUsersTeamContextValue: UsersTeamContextType = {
        ...defaultMemoizedContextValue,
        getValue: () => ({
          users: [],
        }),
        addUser: () => {},
        assignScore: () => {},
       };
      
    • 为您的动作创建类型 - 您将使用它们来修改上下文值 :
      export interface AddUserAction extends MemoizedContextAction {
        type: 'addUser';
        data?: { user: User };
      }
        
      export interface AssignScoreAction extends MemoizedContextAction {
        type: 'assignScore';
        data?: { userId: User['id']; score: number };
      }
        
      export type UserTeamContextActions = AddUserAction | AssignScoreAction;
      
  2. 创建上下文 :

    const UsersTeamContext = createContext<UsersTeamContextType>(defaultUsersTeamContextValue);
    
    const useUsersTeamContext = () => useContext(UsersTeamContext);
    
  3. 创建您的调度方法 。 它应该像 reduux 调度一样工作 - 采取行动,修改状态值并返回一个新的状态:

    export const usersTeamContextDispatch = (state: UsersTeamContextValue, action: UserTeamContextActions) => {
      switch (action.type) {
        case 'assignScore':
          return {
            ...state,
            users: state.users.map((user) => {
              if (user.id === action.data?.userId) {
                return {
                  ...user,
                  score: action.data?.score ?? 0,
                };
              }
              return user;
            }),
          };
        case 'addUser':
          return {
            ...state,
            users: action.data ? [...state.users, action.data.user] : state.users,
          };
      }
    };
    
  4. 创建您的提供者 :

    export const UsersTeamProvider = ({ children }: PropsWithChildren<{}>) => {
      
      const { contextValue } = useMemoizedContextProvider<UsersTeamContextValue>(
        // provide default value for your context
        {
          users: [],
        },
        usersTeamContextDispatch,
      );
    
      // create methods you want to expose to clients
      const addUser = useCallback((user: User) => contextValue.dispatch({ type: 'addUser', data: { user } }), [contextValue]);
    
      const assignScore = useCallback(
        (userId: User['id'], score: number) => contextValue.dispatch({ type: 'assignScore', data: { userId, score } }),
        [contextValue],
      );
    
      // memoize your final value that will be available for clients
      // just return what's in contextValue and add your methods
      const value = useMemo<UsersTeamContextType>(
        () => ({
          ...contextValue,
          addUser,
          assignScore,
        }),
        [addUser, assignScore, contextValue],
      );
    
      return <UsersTeamContext.Provider value={value}>{children}</UsersTeamContext.Provider>;
    };
    
  5. 要从上下文中获取数据, 您需要选择 :

    export const usersTeamUsersSelector = (state: UsersTeamContextValue) => state.users;
    

    组件中的用法 :

    const context = useUsersTeamContext();
    // pass context to useMemoizedContextSelector
    const users = useMemoizedContextSelector(context, usersTeamUsersSelector);
    

    为了简化它,您可以创建一个助手:

    export function useUsersTeamContextSelector<T>(selector: (st: UsersTeamContextValue) => T) {
      const context = useUsersTeamContext();
      return useMemoizedContextSelector(context, selector);
    }
    
    

    那么,来取回 users 从上下文可以做到:

    const users = useUsersTeamContextSelector(usersTeamUsersSelector);
    
  6. 开始用上下文!

    将组件与您的 Provider 组件,如同您在 React 语境中所做的:

    <UsersTeamProvider>
        <UsersTeam name="Team 1" />
    </UsersTeamProvider>
    
To modify context value, use any of your actions:

```typescript
import { useUsersTeamContextSelector } from "./usersTeamContext";

const { addUser } = useUsersTeamContext()

const onClick = () => {
  addUser({ name: 'John' })
}

```

You can read context values on the fly if you need. For example, we will create a user with `users.length` as id. We can use `usersTeamUsersSelector`, but the component would be rerendered every time when any user changes. We don't want that - we need just `users` length. We could create a selector that gets users length, but again - everytime we add a user, the component will rerender. For us, it's enough to know users length by the time we create a user:
```typescript
 // get whole context value - it will not cause any rerender!
 const contextValue = useUsersTeamContext();

  const addNewUser = () => {
    // read users array when we need it
    const users = contextValue.getValue().users;
    // call addUser action to add a new user
    contextValue.addUser({ id: users.length + 1, name: userName, score: 0 });
  };
```

密码框

您可以使用代码和框播放示例 : https://codesandbox.io/s/boring-morning-j44i9p (中文(简体) )

版本与发布记录

@air/react-memoized-context 共发布 3 个版本,首次发布于 2022/08/09;过去 12 个月发布了 0 个版本。

版本发布日期距今
1.0.2latest2025/03/041.7 年前
1.0.12025/03/011.7 年前
1.0.02022/08/094 年前

关于 @air/react-memoized-context 的常见问题

@air/react-memoized-context 是什么?

使用您的 React 上下文而不附加在消费者中的重报 - 从上下文“ 飞上” 读取值的能力 - 在回调中有用, 这样您无需将 UI 绑定到上下文值变化中, 只是为了使用回调值 - Redux- l

如何安装 @air/react-memoized-context?

在项目目录运行 npm install @air/react-memoized-context,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=17)、react-dom(>=17)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@air/react-memoized-context 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@air/react-memoized-context 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@air/react-memoized-context 可以商用吗?

@air/react-memoized-context 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@air/react-memoized-context 的下载量有多少?

根据 npm 官方下载统计,@air/react-memoized-context 在 2026/10/05 – 2026/11/03 这 30 天内被下载 28,236 次,日均约 941 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@air/react-memoized-context 还在维护吗?

最新版本 1.0.2 发布于 2025/03/04(1.7 年前);至今共发布 3 个版本,其中过去 12 个月发布了 0 个;首次发布于 2022/08/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。