All files / react-tao/src Reactor.js

100% Statements 19/19
100% Branches 9/9
100% Functions 7/7
100% Lines 19/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109        3x                                           23x         11x 11x       11x   11x             11x 11x 3x 3x                 11x                                                         7x         24x 24x 14x   8x 8x 1x   7x                  
import React from 'react';
 
/** @typedef {import('./Adapter').default} Adapter */
 
const DUMMY_STATE = {};
 
/**
 * Props for {@link Reactor}: the adapter plus passthrough props spread onto
 * whichever component the adapter's current match renders.
 * @typedef {{ adapter: Adapter } & Object<string, *>} ReactorProps
 */
 
/**
 * Original ("orig" entry) API: renders the component its {@link Adapter}
 * registered for the most recent matching AppCon — or nothing before any
 * match. The rendered component receives the trigram (`t`/`a`/`o`), the
 * Reactor's passthrough props, and the registration props merged with the
 * AppCon data. NOTE: children are ignored.
 * Legacy — prefer `RenderHandler` / `SwitchHandler` from the package root.
 * @extends {React.Component<ReactorProps>}
 */
class Reactor extends React.Component {
  /**
   * @param {ReactorProps} props
   */
  constructor(props) {
    super(props);
    // this._adapter = adapter;
  }
 
  componentDidMount() {
    const { adapter } = this.props;
    adapter.registerReactor(this, this.onNotifyChange.bind(this));
  }
 
  componentWillUnmount() {
    const { adapter } = this.props;
    // Stryker disable next-line all: defensive optional calls; ReactorProps requires adapter
    adapter && adapter.unregisterReactor && adapter.unregisterReactor(this);
  }
 
  /**
   * @param {ReactorProps} prevProps
   */
  componentDidUpdate(prevProps) {
    const { adapter } = this.props;
    if (adapter !== prevProps.adapter) {
      prevProps.adapter.unregisterReactor(this);
      adapter.registerReactor(this, this.onNotifyChange.bind(this));
    }
  }
 
  /**
   * @param {ReactorProps} nextProps
   * @returns {boolean}
   */
  shouldComponentUpdate(nextProps) {
    return true;
  }
  //   // TODO: Implement this properly
  //   // CURRENTLY: this.props.adapter already has the changes after a TAO Handler
  //   const { adapter, children, ...props } = this.props;
  //   if (adapter !== nextProps.adapter) {
  //     return true;
  //   }
  //   if (
  //     (adapter.current == null && nextProps.adapter.current != null) ||
  //     (adapter.current != null && nextProps.adapter.current == null)
  //   ) {
  //     return true;
  //   }
  //   if (adapter.current == null && nextProps.adapter.current == null) {
  //     return false;
  //   }
  //   // TODO: if the term, action, orient or any other props change for the same
  //   //  Component, if this returns `false` will React still call render on the
  //   //  Component
  //   if (adapter.current.Component !== nextProps.adapter.current.Component) {
  //     return true;
  //   }
  //   // TODO: figure out if need to perform props equality check
  //   //  - by checking if updated props get sent to re-rendered child
  //   return false;
  // }
 
  onNotifyChange() {
    this.setState(DUMMY_STATE);
  }
 
  render() {
    // NOTE: Currently swallows any children
    const { adapter, children, ...props } = this.props;
    if (!adapter.current) {
      return null;
    }
    const { ComponentHandler, tao, props: childProps } = adapter.current;
    if (!ComponentHandler) {
      return null;
    }
    return React.createElement(ComponentHandler, {
      ...tao,
      ...props,
      ...childProps,
    });
  }
}
 
export default Reactor;