atom管理state,

selector选择atom后做拦截中间层处理

实现代码

import { useState, useCallback, useEffect } from 'react';
/**
 * 1.订阅
 * 2.发布
 * 3.更新
 * 4.快照
 * 5.事件发布
 */
interface Dissconnect {
    disconnect: () => void
}
class StateFul<T>{
    constructor(protected value: T) {
    }
    private listener = new Set<(value: T) => void>();
    public subscribe(callback: (value: T) => void): Dissconnect {
        this.listener.add(callback);
        return {
            disconnect: () => {
                this.listener.delete(callback)
            }
        }
    }
    public list() {
        return this.listener;
    }
    public snapShot() {
        return this.value;
    }
    public update(value: T) {
        if (this.value !== value) {
            this.value = value;
            this.emit();
        }
    }
    protected emit() {
        this.listener.forEach(callback => callback(this.value));
    }
}
class Atom<T> extends StateFul<T>{
    public setState(value: T): void {
        this.update(value);
    }
}
class Selector<T> extends StateFul<T>{
    constructor(private readonly generate: SelectorGenerator<T>) {
        super(undefined as any);
        this.value = this.generate({get:(dep:Atom<any>)=>this.addDep(dep)});
    }
    private register = new Set<Atom<any>>();
    public addDep(dep:Atom<any>){
        if(!this.register.has(dep)){
            dep.subscribe(()=>this.updateSelector())
            this.register.add(dep)
        }
        return dep.snapShot();
    }
    private updateSelector(){
        this.update(this.generate({get:(dep:Atom<any>)=>this.addDep(dep)}));
    }
}

export function atom<V>(value: { key: string, defaultValue: V }) {
    return new Atom(value.defaultValue);
}
type SelectorGenerator<V> = (context: { get: <T>(dep: Atom<T>) => T }) => V;

export function selector<V>(value: { key: string; get: SelectorGenerator<V> }) {
    return new Selector(value.get);
}
export function useRecoilState<T>(atom: StateFul<T>) {
    const value = useRecoilValue(atom);
    return [value,
        useCallback((value: T) => {
            atom.update(value);
        }, [atom])
    ] as const;
}
export function useRecoilValue<T>(value: StateFul<T>) {
    const [state, setState] = useState({});
    console.log(123, value.list(), state)
    // value没变就不执行注册
    useEffect(() => {
        // value触发时,将setState注册到value的callback列表中,
        // update被调用时,触发setState,setState触发组件重新渲染。
        const { disconnect } = value.subscribe(() => setState({}));
        return () => {
            disconnect();
        }
    }, [value])
    return value.snapShot();
}

外部调用部分

import React, { ChangeEvent } from 'react';
import logo from './logo.svg';
import './App.css';
import { atom, selector, useRecoilState, useRecoilValue } from './recoil/index';

const textState = atom({
  key: 'textState',
  defaultValue: 'Hello World'
});

const charCountState = selector({
  key: 'charCountState',
  get: ({ get }) => {
    const text = get(textState);
    return text ? text.length : 0;
  },
});
function App() {
  // const txt = useRecoilValue(textState);
  const [text, setText] = useRecoilState(textState);
  const onChange = (event: ChangeEvent<HTMLInputElement>) => {
    setText(event.target.value);
  }
  const a = useRecoilValue(charCountState)
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          {/* Edit <code>src/App.tsx</code> and save to reload. */}
          <input type='text' value={text} onChange={onChange}></input>
        </p>
        <a
          className="App-link"
          href="<https://reactjs.org>"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
        {text}
        <p></p>
        selector:
        {a}
        {/* {txt} */}
      </header>
    </div>
  );
}

export default App;