组件间通讯

组件间的通讯有很多种,常见的主要是父子组件之间、同级组件之间和任意组件之间。

父子组件通讯

父子组件通讯主要依靠props。父组件可以通过props将信息传递给子组件,子组件还可以通过props中父组件指定的回调函数来将信息传递回父组件。具体实现可参考以下示例。

// 父组件
function ParentElement() {
  const [info, setInfo] = useState(0);

  const handleChange = (e) => {
    setInfo(e);
  };

  return <ChildElement value={info} onValueChange={handleChange} />;
}

// 子组件
function ChildElement(props) {
  const handleChange = (e) => {
    props.onValueChange(e.target.value);
  };

  return <input value={props.value} onChange={handleChange} />;
}

同级组件通讯

同级组件之间的通讯无论使用哪种方案解决,都还是需要其共同的父级组件来介导一下的。除了可以使用上面提到的父子组件通讯方法,还可以使用 Context 来形成一个 API 来传递通讯。

const SharedStateContext = createContext();

const ParentComponent = () => {
  const [sharedState, setSharedState] = useState("");

  return (
    <SharedStateContext.Provider value={{ sharedState, setSharedState }}>
      <ChildComponentA />
      <ChildComponentB />
    </SharedStateContext.Provider>
  );
};

const ChildComponentA = () => {
  const { sharedState, setSharedState } = useContext(SharedStateContext);

  return (
    <div>
      <input
        type="text"
        value={sharedState}
        onChange={(e) => setSharedState(e.target.value)}
        placeholder="Type in A"
      />
    </div>
  );
};

const ChildComponentB = () => {
  const { sharedState } = useContext(SharedStateContext);

  return (
    <div>
      <p>Shared state in B: {sharedState}</p>
    </div>
  );
};

任意组件间通讯

任意组件之间的通讯就要复杂一些了,首先的困难就是无法确定组件之间的共同祖先,其次如果将大量的 Context API 放置在应用的根节点上,可能会给应用带来不必要的开销。所以在这种情况下,可以利用现有的事件系统来实现,或者字型构建一个事件系统。这里借用events库来完成任意组件之间的通讯。

import EventEmitter from "events";
import { useEffect, useState } from "react";

const eventEmitter = new EventEmitter();

const ChildComponentA = () => {
  const [value, setValue] = useState("");

  const handleChange = (e) => {
    setValue(e.target.value);
    eventEmitter.emit("update", e.target.value);
  };

  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={handleChange}
        placeholder="Type in A"
      />
    </div>
  );
};

const ChildComponentB = () => {
  const [sharedState, setSharedState] = useState("");

  useEffect(() => {
    eventEmitter.on("update", setSharedState);
    return () => {
      eventEmitter.off("update", setSharedState);
    };
  }, []);

  return (
    <div>
      <p>Shared state in B: {sharedState}</p>
    </div>
  );
};

const ParentComponent = () => (
  <div>
    <ChildComponentA />
    <ChildComponentB />
  </div>
);