UNPKG

r-ninja

Version:

r-ninja watches for changes in JSX expressions and updates UI with very less glue code.

66 lines (65 loc) 1.9 kB
import React, { useContext, useState, useEffect } from "react"; import { Watcher } from "./watcher"; let refreshPlanned = false; export const check = () => { if (refreshPlanned) { return; } refreshPlanned = true; requestAnimationFrame(() => { Watcher.ROOT.check(); refreshPlanned = false; }); }; export const NinjaContext = React.createContext(null); export class PropsWatcher extends React.Component { constructor(props) { super(props); this.watcher = null; this.refresh = () => { this.setState({ id: this.state.id + 1 }); }; this.state = { id: 0 }; } shouldComponentUpdate(nextProps, nextState) { return (this.state.id !== nextState.id || this.watcher.isDestroyed) || Object.keys(nextProps).reduce((p, k) => { return p || (k !== 'render' && this.props[k] !== nextProps[k]); }, false); } componentWillUnmount() { this.watcher && this.watcher.destroy(); } watch(fn) { return this.watcher.watch(fn, this.refresh).value; } render() { return React.createElement(NinjaContext.Consumer, null, ((parent) => { parent = parent || Watcher.ROOT; this.watcher = this.watcher || parent.create(); this.watcher.clear(); return this.props.render(this.watch.bind(this)); })); } } export function useWatcher() { const parent = useContext(NinjaContext); const [change, onChange] = useState({}); let [watcher] = useState(() => parent.create()); watcher.clear(); useEffect(() => { return () => { watcher.destroy(); }; }, [watcher]); return { watch: (fn) => { return watcher.watch(fn, () => onChange({})).value; } }; } ;