<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      useSyncExternalStore 的應用

      我們是袋鼠云數棧 UED 團隊,致力于打造優秀的一站式數據中臺產品。我們始終保持工匠精神,探索前端道路,為社區積累并傳播經驗價值。

      本文作者:修能

      學而不思則罔,思而不學則殆 。 --- 《論語·為政》

      What

      useSyncExternalStore is a React Hook that lets you subscribe to an external store.

      useSyncExternalStore 是一個支持讓用戶訂閱外部存儲的 Hook。官方文檔


      const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)
      

      Why

      首先,我們這里基于 molecule1.x 的版本抽象了一個簡易版的 mini-molecule。

      import { EventBus } from "../utils";
      
      type Item = { key: string };
      // 聲明一個事件訂閱
      const eventBus = new EventBus();
      // 聲明模塊數據類型
      class Model {
        constructor(public data: Item[] = [], public current?: string) {}
      }
      
      export class Service {
        protected state: Model;
        constructor() {
          this.state = new Model();
        }
      
        setState(nextState: Partial<Model>) {
          this.state = { ...this.state, ...nextState };
          this.render(this.state);
        }
      
        private render(state: Model) {
          eventBus.emit("render", state);
        }
      }
      
      export default function Home() {
        const state = useExternal();
        if (!state) return <div>loading...</div>;
        return (
          <>
            <strong>{state.current || "empty"}</strong>
            <ul>
              {state.data.map((i) => (
                <li key={i.key}>{i.key}</li>
              ))}
            </ul>
          </>
        );
      }
      
      const service = new Service();
      function useExternal() {
        const [state, setState] = useState<Model | undefined>(undefined);
      
        useEffect(() => {
          setState(service.getState());
          service.onUpdateState((next) => {
            setState(next);
          });
        }, []);
      
        return state;
      }
      

      如上面代碼所示,已經實現了從外部存儲獲取相關數據,并且監聽外部數據的更新,并觸發函數組件的更新。

      接下來實現更新外部數據的操作。

      export default function Home() {
        const state = useExternal();
        if (!state) return <div>loading...</div>;
        return (
          <>
            <ul>
              {state.data.map((i) => (
                <li key={i.key}>{i.key}</li>
              ))}
            </ul>
      +      <button onClick={() => service.insert(`${new Date().valueOf()}`)}>
      +        add list
      +      </button>
          </>
        );
      }
      
      

      其實要做的比較簡單,就是增加了一個觸發的按鈕去修改數據即可。


      上述這種比較簡單的場景下所支持的 useExternal 寫起來也是比較簡單的。當你的場景越發復雜,你所需要考慮的就越多。就會導致項目的復雜度越來越高。而此時,如果有一個官方出品,有 React 團隊做背書的 API 則會舒服很多。

      以下是 useSyncExternlaStore 的 shim 版本相關代碼:

      function useSyncExternalStore(subscribe, getSnapshot, // Note: The shim does not use getServerSnapshot, because pre-18 versions of
                                    // React do not expose a way to check if we're hydrating. So users of the shim
                                    // will need to track that themselves and return the correct value
                                    // from `getSnapshot`.
                                    getServerSnapshot) {
        {
          if (!didWarnOld18Alpha) {
            if (React.startTransition !== undefined) {
              didWarnOld18Alpha = true;
      
              error('You are using an outdated, pre-release alpha of React 18 that ' + 'does not support useSyncExternalStore. The ' + 'use-sync-external-store shim will not work correctly. Upgrade ' + 'to a newer pre-release.');
            }
          }
        } // Read the current snapshot from the store on every render. Again, this
        // breaks the rules of React, and only works here because of specific
        // implementation details, most importantly that updates are
        // always synchronous.
      
      
        var value = getSnapshot();
      
        {
          if (!didWarnUncachedGetSnapshot) {
            var cachedValue = getSnapshot();
      
            if (!objectIs(value, cachedValue)) {
              error('The result of getSnapshot should be cached to avoid an infinite loop');
      
              didWarnUncachedGetSnapshot = true;
            }
          }
        } // Because updates are synchronous, we don't queue them. Instead we force a
        // re-render whenever the subscribed state changes by updating an some
        // arbitrary useState hook. Then, during render, we call getSnapshot to read
        // the current value.
        //
        // Because we don't actually use the state returned by the useState hook, we
        // can save a bit of memory by storing other stuff in that slot.
        //
        // To implement the early bailout, we need to track some things on a mutable
        // object. Usually, we would put that in a useRef hook, but we can stash it in
        // our useState hook instead.
        //
        // To force a re-render, we call forceUpdate({inst}). That works because the
        // new object always fails an equality check.
      
      
        var _useState = useState({
          inst: {
            value: value,
            getSnapshot: getSnapshot
          }
        }),
          inst = _useState[0].inst,
          forceUpdate = _useState[1]; // Track the latest getSnapshot function with a ref. This needs to be updated
        // in the layout phase so we can access it during the tearing check that
        // happens on subscribe.
      
      
        useLayoutEffect(function () {
          inst.value = value;
          inst.getSnapshot = getSnapshot; // Whenever getSnapshot or subscribe changes, we need to check in the
          // commit phase if there was an interleaved mutation. In concurrent mode
          // this can happen all the time, but even in synchronous mode, an earlier
          // effect may have mutated the store.
      
          if (checkIfSnapshotChanged(inst)) {
            // Force a re-render.
            forceUpdate({
              inst: inst
            });
          }
        }, [subscribe, value, getSnapshot]);
        useEffect(function () {
          // Check for changes right before subscribing. Subsequent changes will be
          // detected in the subscription handler.
          if (checkIfSnapshotChanged(inst)) {
            // Force a re-render.
            forceUpdate({
              inst: inst
            });
          }
      
          var handleStoreChange = function () {
            // TODO: Because there is no cross-renderer API for batching updates, it's
            // up to the consumer of this library to wrap their subscription event
            // with unstable_batchedUpdates. Should we try to detect when this isn't
            // the case and print a warning in development?
            // The store changed. Check if the snapshot changed since the last time we
            // read from the store.
            if (checkIfSnapshotChanged(inst)) {
              // Force a re-render.
              forceUpdate({
                inst: inst
              });
            }
          }; // Subscribe to the store and return a clean-up function.
      
      
          return subscribe(handleStoreChange);
        }, [subscribe]);
        useDebugValue(value);
        return value;
      }
      

      How

      針對上述例子進行改造

      const service = new Service();
      
      export default function Home() {
        const state = useSyncExternalStore(
          (cb) => () => service.onUpdateState(cb),
          service.getState.bind(service)
        );
      
        if (!state) return <div>loading...</div>;
        return (
          <>
            <ul>
              {state.data.map((i) => (
                <li key={i.key}>{i.key}</li>
              ))}
            </ul>
            <button onClick={() => service.insert(`${new Date().valueOf()}`)}>
              add list
            </button>
          </>
        );
      }
      
      

      在 Molecule 中使用

      import { useContext, useMemo } from 'react';
      import type { IMoleculeContext } from 'mo/types';
      import { useSyncExternalStore } from 'use-sync-external-store/shim';
      
      import { Context } from '../context';
      
      type Selector = keyof IMoleculeContext;
      type StateType<T extends keyof IMoleculeContext> = ReturnType<IMoleculeContext[T]['getState']>;
      
      export default function useConnector<T extends Selector>(selector: T) {
          const { molecule } = useContext(Context);
          const target = useMemo(() => molecule[selector], [molecule]);
          const subscribe = useMemo(() => {
              return (notify: () => void) => {
                  target.onUpdateState(notify);
                  return () => target.removeOnUpdateState(notify);
              };
          }, []);
          return useSyncExternalStore(subscribe, () => target.getState()) as StateType<T>;
      }
      

      最后

      歡迎關注【袋鼠云數棧UED團隊】~
      袋鼠云數棧 UED 團隊持續為廣大開發者分享技術成果,相繼參與開源了歡迎 star

      posted @ 2025-03-20 10:16  袋鼠云數棧前端  閱讀(91)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 毛片av在线尤物一区二区| 久久国产成人精品国产成人亚洲 | 亚洲高请码在线精品av| 亚洲一区国色天香| 女同亚洲精品一区二区三| 2020国产成人精品视频| 亚洲精品乱码久久久久久蜜桃图片| 国产精品内射在线免费看| 国产永久免费高清在线观看| 91在线国内在线播放老师| 久久香蕉国产线看观看怡红院妓院 | 免费无码黄十八禁网站| 2019nv天堂香蕉在线观看| 性色a码一区二区三区天美传媒| 中文字幕亚洲国产精品| 国产日产欧美最新| 国产精品无码av在线一区 | 人妻精品久久无码区| 放荡的少妇2欧美版| 国产精品美女久久久久久麻豆 | 美女扒开奶罩露出奶头视频网站 | 女同精品女同系列在线观看| 视频一区视频二区在线视频| 三级黄色片一区二区三区| 国产女人喷潮视频免费| 欧美交a欧美精品喷水| 综合色在线| 国产区免费精品视频| 悠悠人体艺术视频在线播放| 99精品全国免费观看视频| 国产精品99区一区二区三| 欧美日韩精品一区二区三区高清视频| 无码免费大香伊蕉在人线国产| 中字幕人妻一区二区三区| 色伦专区97中文字幕| 亚洲护士一区二区三区| 精品久久久久中文字幕日本| 成人国产精品中文字幕| 日本污视频在线观看| 蜜桃无码一区二区三区| 国产一区二区三区怡红院|