React useSyncExternalStore 的自定义实现

创建store

const createStore = (initialState) => {
  let state = initialState;
  //snapshot
  const getState = () => state;
  
  const listeners = new Set();
  //dispatch
  const setState = (fn) => {
    state = fn(state);
    listeners.forEach((l) => l());
  }
  const subscribe = (listener) => {
    listeners.add(listener);
    return () => listeners.delete(listener);
  }
  return {getState, setState, subscribe}
}

将store封装成hook

const useStore = (store, selector) => {
  // selector是获取指定 state 的方法
  const [state, setState] = useState(() => selector(store.getState()));
  
  useEffect(() => {
    const callback = () => setState(selector(store.getState()));
    // 注意这里的callback用setState包裹,当触发订阅器的时候,就会返回新的state
    const unsubscribe = store.subscribe(callback);
    callback();
    return unsubscribe;
  }, [store, selector]);
  
  return state;
}

组件中使用

const store = createStore({count: 0, text: 'hello'});

const Counter = () => {
  const count = useStore(store, useCallback((state) => state.count, []));
  const inc = () => {
    //store.setState会触发订阅器,重新返回新的store state
    store.setState((prev) => ({...prev, count: prev.count + 1}))
  }
  return (
    <div>
      {count} <button onClick={inc}>+1</button>
    </div>
  );
}

通过 useSyncExternalStore 替换

  • 由上述可知,useSyncExternalStore 第一个参数是订阅器,会将第二个参数添加进去,然后通过 useState 返回值,这样当订阅器进行发布的时候,再此调用第二个参数,setState 最新的结果来更新组件
import { useSyncExternalStore } from 'react';

const useStore = (store, selector) => {
  return useSyncExternalStore(
    store.subscribe,
    useCallback(() => selector(store.getState(), [store, selector]))
  )
}
==============================之前的useStore
const useStore = (store, selector) => {
  // selector是获取指定 state 的方法
  const [state, setState] = useState(() => selector(store.getState()));
  
  useEffect(() => {
    const callback = () => setState(selector(store.getState()));
    // 注意这里的callback用setState包裹,当触发订阅器的时候,就会返回新的state
    const unsubscribe = store.subscribe(callback);
    callback();
    return unsubscribe;
  }, [store, selector]);
  
  return state;
}


getSnapshot 不要每次返回新对象

  • useSyncExternalStore 是否更新组件,依赖于第二个参数的返回值,所以不要每次都返回一个新对象
    import { useSyncExternalStore } from 'react';

    export function useOnlineStatus() {
      const isOnline = useSyncExternalStore(subscribe, getSnapshot);
      return isOnline;
    }

    function getSnapshot() {
      return navigator.onLine;
    }

    function subscribe(callback) {
      window.addEventListener('online', callback);
      window.addEventListener('offline', callback);
      return () => {
        window.removeEventListener('online', callback);
        window.removeEventListener('offline', callback);
      };
    }

function getSnapshot() {
  // 🔴 getSnapshot 不要总是返回新的对象
  return {
    todos: myStore.todos
  };
}

function getSnapshot() {
  // ✅ 数据不变时不会触发更新
  return myStore.todos;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
react自定义hook的实现非常简单。你只需要将常规的函数和逻辑包装在一个名称以 use 开头的函数里面,就可以将其作为自定义 hook 使用。例如,下面是一个 useEffect 自定义 hook 的示例代码: ``` import React, { useState, useEffect } from 'react'; function useCustomHook(myValue) { const [count, setCount] = useState(0); useEffect(() => { console.log(`my value is: ${myValue}`); console.log(`count is: ${count}`); }, [count, myValue]); function handlePlus() { setCount(count + 1); } function handleMinus() { setCount(count - 1); } return { count, handlePlus, handleMinus, }; } ``` 在这里,我们创建了一个名为 useCustomHook 的函数。该函数接受一个名为 myValue 的参数。我们在 useCustomHook 函数中使用 useState 和 useEffect。我们返回一个对象,该对象包含 count 值以及处理加法和减法的函数。 接下来,您可以将 useCustomHook 导入包含您的 react 程序的文件,并使用对它调用以前定义的函数来调用它。例如: ``` import React from 'react'; import { useCustomHook } from './useCustomHook'; function App() { const { count, handlePlus, handleMinus } = useCustomHook('my value'); return ( <div> <p>Count is: {count}</p> <button onClick={handlePlus}>Plus</button> <button onClick={handleMinus}>Minus</button> </div> ); } export default App; ``` 在这里,我们导入 useCustomHook,然后从调用它的返回对象中提取 count、处理加法和减法的函数。 这就是一个简单的自定义 hook 的范例。你可以创建任意数量的自定义 hook,从而封装 React 组件中的常见逻辑和代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值