redux不会用,要不自己写一个

136 阅读2分钟

在写react是需要组件和组件之间的通信,本来想用redux,但自己忘了怎么用了,翻文档又太累,感觉很麻烦,所以就只能自己动手写一个,才能维持下生活这样子。 其实核心也就不到70行代码这个样子, 就下面这样子。

import { useEffect, useState } from 'react';

type SubscriptionHandler = number;

interface SubscriptionServiceInterface<T> {
  value: T;

  next(patchData: T): boolean;

  subscription(patchDataCallback: (patchData: T) => void): SubscriptionHandler;

  unSubscription(subscriptionHandler: SubscriptionHandler): boolean;

  complete(): void;
}

export default class SubscriptionService<T> implements SubscriptionServiceInterface<T> {
  history: { time: Date; data: T }[] = [];
  private subscriptions: Map<number, (patchData: T) => void> = new Map<number, (patchData: T) => void>();
  value: T;

  isComplete: boolean = false;

  constructor(value: T) {
    this.value = value;
  }

  next(patchData: T): boolean {
    if (this.isComplete) {
      return false;
    }
    this.history = [...this.history, { time: new Date(), data: this.value }];
    this.value = patchData;
    this.subscriptions.forEach((callback) => callback(this.value));

    return true;
  }

  subscription(patchDataCallback: (patchData: T) => void): SubscriptionHandler {
    const subscriptionHandler = this.subscriptions.size + 1;
    this.subscriptions.set(subscriptionHandler, patchDataCallback);

    return subscriptionHandler;
  }

  unSubscription(subscriptionHandler: SubscriptionHandler): boolean {
    return !this.subscriptions.has(subscriptionHandler) ? false : this.subscriptions.delete(subscriptionHandler);
  }

  complete(): void {
    this.isComplete = true;
    this.subscriptions.clear();
  }
}

export const useObserve = <T>(observe: SubscriptionService<T>): [T, SubscriptionService<T>] => {
  const [value, setValue] = useState<T>(observe.value);
  useEffect(() => {
    const subscriptionHandler = observe.subscription((newValue) => setValue(newValue));

    return () => {
      observe.unSubscription(subscriptionHandler);
    };
  }, []);

  return [value, observe];
};

本质就是一个事件订阅和事件发布。

2 使用前需要声明一个公共的类作为组件和组件之间的调度器

其实这个调度器,其实就是一个有静态属性的类,作用就是保证组件和组件之间使用的是一个内存,这样一来,有一个组件发布事件了,另一个也是使用这一内存作为事件的订阅的组件,就能被回调了,从而实现了组件和组件之间的通信。调度器的代码就这样了:

import SubscriptionService from "@wuchuheng/rxjs";

export default class Scheduler {
    // 声明一个共享会话的聊天室
    public static chatGroupObserve = new SubscriptionService<string>('');
}

3然后就可以直接在各个组件中使用了

如:

import React from "react";
import style from './style.module.scss';
import {useObserve} from "@wuchuheng/rxjs";
import Scheduler from "./Scheduler";

type BossPropsType = {name: string, quotes: string[]}
const bosses: BossPropsType[] = [
    {name: '雷不死', quotes: ['Hello!', 'Thank you very mach!', 'Are you ok!', '这他妈的绝对是来捣乱的!!!']},
    {name: '王一亿', quotes: ['定个小目标', '赚它一个亿']},
    {name: '杰克马', quotes: ['996是福报', '向社会输送人才']},
    {name: '麻花疼', quotes: ['充钱让你更强', '南山必胜客']},
]

const formatTime = (time: Date): string => `${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}`

const Boss = (props: BossPropsType): React.ReactElement => {
    const [message, dispatcher] = useObserve(Scheduler.chatGroupObserve)
    const handleChange = (e: string) => dispatcher.next(`${props.name}: ${e}`)

    return (
        <div className={style.bossWrapper}>
            <div>大佬: {props.name}</div>
            <div>
                <div>他想说:</div>
                <select onChange={(e) => handleChange(e.target.value) }>
                    {props.quotes.map(q => <option value={q} key={q}>{q}</option>)}
                </select>
                <div>最新消息: <span>{message}</span></div>
            </div>
            <div className={style.history}>
                <div>历史记录:</div>
                <div className={style.history}>
                    {
                        dispatcher.history.map(
                            (m, k) =>
                                <p key={k}>
                                    {formatTime(m.time)} {m.data}
                                </p>
                        )
                    }
                </div>
            </div>
        </div>
    )
}
const CustomRedux = (): React.ReactElement => {
    const BossesRender = (
        bosses.map(
            (bossInfo, k) => <Boss
                name={bossInfo.name}
                quotes={bossInfo.quotes} key={k}
            />
        )
    )
    return (
        <div className={style.main}>
            <h1>看看大佬们都说了什么?</h1>
            <div className={style.container}>
                {BossesRender}
            </div>
        </div>
    )
}

export default CustomRedux

Edit note-demo-for-react <-- 线上示例在这里,自己看

源码仓库