惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
IT之家
IT之家
博客园_首页
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
小众软件
小众软件
博客园 - 叶小钗
WordPress大学
WordPress大学
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 三生石上(FineUI控件)
罗磊的独立博客
博客园 - Franky
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
T
Tailwind CSS Blog
宝玉的分享
宝玉的分享
博客园 - 【当耐特】
月光博客
月光博客
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理

szhshp 的第三边境研究所

假设, AI 把我代替的那一刻真的到来 | szhshp 的第三边境研究所 小傻瓜都能懂的 AstrBot QQ 机器人集成 MCP 功能实战指南 | szhshp 的第三边境研究所 《智人之上: 从石器时代到 AI 时代的信息网络简史》阅读笔记 | szhshp 的第三边境研究所 iPadOS 26 无法设置空间场景图片壁纸的解决方法 | szhshp 的第三边境研究所 《一路云海》(终) | szhshp 的第三边境研究所 《一路云海》(四): 如何不按套路旅行 | szhshp 的第三边境研究所 《一路云海》(三): In Ya Mellow Tone | szhshp 的第三边境研究所 《一路云海》(二): 关西世博参观纪实 | szhshp 的第三边境研究所 《一路云海》(一): 新的征程 | szhshp 的第三边境研究所 2025 大阪世博会 [ 3 天前-先到先得 ] 阶段 场馆预约必中独家攻略 | szhshp 的第三边境研究所 Hackathon 随想 | szhshp 的第三边境研究所 一杯双皮奶 | szhshp 的第三边境研究所 Armbian + CasaOS + NAS 配置指南 | szhshp 的第三边境研究所 Docker 构建镜像报错: error getting credentials - err: exit status 1, out: `` | szhshp 的第三边境研究所 Disqus RIP! 论过高的维护成本如何治疗固执的坏习惯 | szhshp 的第三边境研究所 炸弹猫桌游变体规则 | szhshp 的第三边境研究所 《小岛经济学》阅读笔记 | szhshp 的第三边境研究所 《金钱心理学》阅读笔记 | szhshp 的第三边境研究所 为知笔记 RIP: 迁移剩余的笔记 | szhshp 的第三边境研究所 2025 博客第十年展望 - 再见我的过去 | szhshp 的第三边境研究所 我在独立游戏里面致敬的作品 | szhshp 的第三边境研究所 《How to make thing faster》阅读笔记 | szhshp 的第三边境研究所 《The Art of Clean Code》阅读笔记 | szhshp 的第三边境研究所 《Clean Architecture: A Craftsman Guide to Software Structure and Design》阅读笔记 | szhshp 的第三边境研究所 《How AI Works》阅读笔记 | szhshp 的第三边境研究所 游戏策划废案 - Project Uranus | szhshp 的第三边境研究所 游戏策划废案 - Project X | szhshp 的第三边境研究所 人生第一款独立游戏开发复盘 | szhshp 的第三边境研究所 Trap of Life | szhshp 的第三边境研究所 如果我用手搓了个暗物质雏形 | szhshp 的第三边境研究所
Create Your Own Redux (Typescript) | szhshp 的第三边境研究所
2020-10-26 · via szhshp 的第三边境研究所

Meta

目录

States

Prepare Initial States + State Type

export const initialState = {
  attributeA: {
    propertyA1: ``,
  },
  attributeB: {
    propertyB1: 0,
  },
  num: 0,
};

export type StateType = {
  attributeA: {
    propertyA1: string;
  };
  attributeB: {
    propertyB1: number;
  };
  num: number;
};

Action

Prepare actions

type ActionMap<M extends { [index: string]: any }> = {
  [Key in keyof M]: M[Key] extends undefined
    ? {
        type: Key;
      }
    : {
        type: Key;
        payload: M[Key];
      };
};

// eslint-disable-next-line no-shadow
export enum ActionType {
  setAttrA = `SET_ATTR_A`,
  setAttrB = `SET_ATTR_B`,
  add = `ADD`,
  reduce = `REDUCE`,
}

/**
 * @name ActionPayload
 * @description Type def for action payloads,
 */
type ActionPayload = {
  [ActionType.setAttrA]: {
    propertyA1: string;
  };
  [ActionType.setAttrB]: {
    propertyB1: number;
  };
  /* Not payloads required for below 2 actions */
  [ActionType.add]: undefined;
  [ActionType.reduce]: undefined;
};

/**
 * @name ActionPayloadDataType
 * @description The type def of the Action Payload Data
 */
export type ActionPayloadDataType = ActionMap<ActionPayload>[keyof ActionMap<ActionPayload>];

Reducer

Prepare the reducer details, NO EDIT STATE DIRECTLY

export const reducers = (
  state: StateType,
  actionData: ActionPayloadDataType,
): StateType => {
  switch (actionData.type) {
    case ActionType.setAttrA:
      return {
        ...state,
        attributeA: {
          ...state.attributeA,
          ...actionData.payload,
        },
      };
    case ActionType.setAttrB:
      return {
        ...state,
        attributeB: {
          ...state.attributeB,
          ...actionData.payload,
        },
      };
    case ActionType.add:
      return {
        ...state,
        num: state.num + 1,
      };
    case ActionType.reduce:
      return {
        ...state,
        num: state.num - 1,
      };
    default:
      return state;
  }
};

Create Provider

Create a HOC for state provider

export const AppContext = createContext<{
  state: StateType;
  dispatch: React.Dispatch<ActionPayloadDataType>;
}>({
  state: initialState,
  dispatch: () => null,
});

/**
 * @name StateProvider
 * @description A HOC to wrap root components for global state manage
 */
export const StateProvider: React.FC = ({ children }) => {
  const [state, dispatch] = useReducer(reducers, initialState);

  return (
    <AppContext.Provider value={{ state, dispatch }}>
      {children}
    </AppContext.Provider>
  );
};

Wrap your root Component


const App: React.FC = () => (
  <StateProvider>
    <RootComponent/>
  </StateProvider>
);

Access Context in any of child components

Now you can use it

const Camera: React.FC = () => {
  const { state, dispatch } = useContext(AppContext);

  return (
    <div>
      {state.num}
      <button onClick={dispatch({
        type: ActionType.add
      })}/>
      <button onClick={dispatch({
        type: ActionType.setAttrB,
        payload: {
          propertyB1: 'dispatch this action to set property B1'
        },
      })}/>
    </div>
  );
};

export default Camera;