使用useSyncExternalStore实现组件通信

在React18的版本中,新添加了一个Hook API:useSyncExternalStore,推荐用于从外部数据源读取和订阅的Hook。
通过使用useSyncExternalStore,也可以用它实现组件间的通信。
import { Fragment, useState, useEffect, useSyncExternalStore, useId } from 'react';
import { createRoot } from 'react-dom/client';

class Store {
  valueCache = null;
  listeners = [];

  subscribe = (listener) => {
    this.listeners.push(listener);

    return () => {
      this.listeners.splice(this.listeners.indexOf(listener), 1);
    };
  };

  getSnapshot = () => {
    return this.valueCache;
  };

  emit() {
    this.listeners.forEach((listener) => listener());
  }

  addValue(value) {
    this.valueCache = { value };
    this.emit();
  }

  clearValue() {
    this.valueCache = null;
  }
}

const store = new Store();

function View(props) {
  const valueCache = useSyncExternalStore(store.subscribe, store.getSnapshot);
  const [state, setState] = useState([]);

  useEffect(function() {
    if (valueCache !== null && valueCache.value) {
      setState((prevState) => [...prevState, valueCache.value]);
      store.clearValue();
    }
  }, [valueCache]);

  return <div>{ state.join(', ') }</div>;
}

function AddValue(props) {
  const id = useId();

  function handleClick(event) {
    const value = document.getElementById(`${ id }-input`).value;

    if (value && value !== '') {
      store.addValue(value);
    }
  }

  return (
    <Fragment>
      <input id={ `${ id }-input` } />
      <button type="button" onClick={ handleClick }>点击</button>
    </Fragment>
  );
}

function App(props) {
  return (
    <div>
      <AddValue />
      <View />
    </div>
  );
}

const root = createRoot(document.getElementById('app'));

root.render(<App />);

代码演示

这个例子展示了如何在一个组件内操作,然后将结果传递给另一个组件。
输入文本
展示文字
empty image
暂无数据