Search code examples
javascriptdomreactjstddflux

Warning: ReactDOMComponent: Do not access .props of a DOM node


I'm receiving this error from new React 0.14.x:

Warning: ReactDOMComponent: Do not access .props of a DOM node; instead, recreate the props as `render` did originally or read the DOM properties/attributes directly from this node (e.g., this.refs.box.className).

it('allows for FluxComponents through the tree via context', () => {
  const flux = new Flux();
  const actions = flux.getActions('test');

  class TopView extends React.Component {
    render() {
      return (
        <FluxComponent flux={flux}>
          <SubView />
        </FluxComponent>
      );
    }
  }

  class SubView extends React.Component {
    render() {
      return <SubSubView />;
    }
  }

  class SubSubView extends React.Component {
    render() {
      return (
        <FluxComponent connectToStores="test">
          <div />
        </FluxComponent>
      );
    }
  }

  const tree = TestUtils.renderIntoDocument(
    <TopView />
  );

  const div = TestUtils.findRenderedDOMComponentWithTag(tree, 'div');

  actions.getSomething('something good');
  expect(div.props.something).to.equal('something good');
});

What is the proper way to get props and context in my situation?

Component looks like:

import React from 'react';
import { instanceMethods, staticProperties } from './reactComponentMethods';
import assign from 'object-assign';

class FluxComponent extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.initialize();

    this.state = this.connectToStores(props.connectToStores, props.stateGetter);

    this.wrapChild = this.wrapChild.bind(this);
  }

  wrapChild(child) {
    return React.cloneElement(
      child,
      this.getChildProps()
    );
  }

  getChildProps() {
    const {
      children,
      render,
      connectToStores,
      stateGetter,
      flux,
      ...extraProps } = this.props;

    return assign(
      { flux: this.getFlux() },
      this.state,
      extraProps
    );
  }

  render() {
    let { children, render: internalRender } = this.props;

    if (typeof internalRender === 'function') {
      return internalRender(this.getChildProps(), this.getFlux());
    }

    if (!children) return null;

    if (!Array.isArray(children)) {
      const child = children;
      return this.wrapChild(child);
    } else {
      return <span>{React.Children.map(children, this.wrapChild)}</span>;
    }
  }
}

assign(
  FluxComponent.prototype,
  instanceMethods
);

assign(FluxComponent, staticProperties);

export default FluxComponent;

Solution

  • So I found a solution to get primitive prop values from DOM components (but for objects you will need React components). It looks as follows:

    it('allows for FluxComponents through the tree via context', () => {
      const flux = new Flux();
      const actions = flux.getActions('test');
    
      class TopView extends React.Component {
        render() {
          return (
            <FluxComponent flux={flux}>
              <SubView />
            </FluxComponent>
          );
        }
      }
    
      class SubView extends React.Component {
        render() {
          return <SubSubView />;
        }
      }
    
      class SubSubView extends React.Component {
        render() {
          return (
            <FluxComponent connectToStores="test">
              <InnerWithData />
            </FluxComponent>
          );
        }
      }
    
      class InnerWithData extends React.Component {
        render() {
          return (
            <div data-something={this.props.something} />
          );
        }
      }
    
      const tree = TestUtils.renderIntoDocument(
        <TopView />
      );
      const div = TestUtils.findRenderedDOMComponentWithTag(tree, 'div');
    
      actions.getSomething('something good');
      expect(div.getAttribute('data-something')).to.equal('something good');
    });
    

    Which basically means that put prop values into DOM attributes.