Skip to content

Files

Latest commit

 

History

History

react-dataflow-dynamic

Observable Example: React + Dataflow (Dynamic Import)

See it live: https://observablehq.github.io/examples/react-dataflow-dynamic/

This modifies the React code generated by the Embed tool to facilitate dataflow between the notebook and the React app. The height state of <App> (React) is passed down to <BrushableScatterplot> (Observable), where it is passed into the Runtime’s module.redefine method. And a setSelection function is passed into the scatterplot component, which it calls in a custom Observer when the selection variable is fulfilled.

This version imports the notebook dynamically, so that you’ll always see the latest published version of the notebook when you load the page, instead of having to deploy a new version of your application. This also sidesteps the issues some bundlers have with Observable file attachments. Contrast with static import.

const {default: notebook} = await import("https://api.observablehq.com/@d3/brushable-scatterplot.js?v=3");

The component is in BrushableScatterplot.js:

function BrushableScatterplot({height, setSelection}) {
  const ref = useRef();
  const [module, setModule] = useState();

  useEffect(() => {
    async function load() {
      // Dynamically load the latest published version of the notebook,
      // https://observablehq.com/@d3/brushable-scatterplot.
      const {default: notebook} = await import("https://api.observablehq.com/@d3/brushable-scatterplot.js?v=3");

      const runtime = new Runtime();
      const main = runtime.module(notebook, name => {
        // Embed the chart.
        if (name === "viewof selection") {
          return new Inspector(ref.current);
        }
        // Propagate selection state from Observable to React.
        if (name === "selection") {
          return {fulfilled: setSelection};
        }
      });
      setModule(main);
      return runtime;
    }
    const promise = load();
    return () => {
      promise.then((runtime) => {
        setModule(undefined);
        runtime.dispose();
      });
    };
  }, []);

  // Propagate height state from React to Observable.
  useEffect(() => {
    if (module !== undefined) {
      module.redefine("height", height);
    }
  }, [height, module]);

  return (
    <div className="BrushableScatterplot">
      <div ref={ref}></div>
      <p>Credit: <a href="https://observablehq.com/@d3/brushable-scatterplot">Mike Bostock</a></p>
    </div>
  );
}