Ad

React Can't Replace Server-side Rendered Node In Browser Callback

- 1 answer

I am using a React boilerplate for a small project: https://github.com/koistya/react-static-boilerplate. This boilerplate renders most HTML server side, but I want to add a few dynamic parts to the client side.

As soon as I render the following component, it breaks on Chrome and Safari:

import React, { Component } from 'react';

class DynamicSomething extends Component {

  constructor(props, context) {
    super(props, context);
    this.state = {
      someValue: "Static"
    };
  }

  componentWillMount() {
    setTimeout(() => {this.setState({someValue: "Dynamic"});}, 1);
  }

  render() {
    return <span>{this.state.someValue}</span>;
  }
}

I get the following error, except in Firefox where it works as intended:

Uncaught TypeError: Failed to execute 'replaceChild' on 'Node': parameter 1 is not of type 'Node'.
(program):36 FIREBASE WARNING: Exception was thrown by user callback. TypeError: Failed to execute 'replaceChild' on 'Node': parameter 1 is not of type 'Node'.
    at TypeError (native)
    at Object.Danger.dangerouslyReplaceNodeWithMarkup (eval at <anonymous> (http://localhost:3000/app.js?1451913362157:2808:3), <anonymous>:140:25)
    at Object.ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID (eval at <anonymous> (http://localhost:3000/app.js?1451913362157:1239:3), <anonymous>:71:27)
    at Object.wrapper [as replaceNodeWithMarkupByID] (eval at <anonymous> (http://localhost:3000/app.js?1451913362157:717:3), <anonymous>:66:21)
    at ReactCompositeComponentMixin._replaceNodeWithMarkupByID (eval at <anonymous> (http://localhost:3000/app.js?1451913362157:2862:3), <anonymous>:579:31)
    at ReactCompositeComponentMixin._updateRenderedComponent (eval at <anonymous> (http://localhost:3000/app.js?1451913362157:2862:3), <anonymous>:571:12)
    at ReactCompositeComponentMixin._performComponentUpdate (eval at <anonymous> (http://localhost:3000/app.js?1451913362157:2862:3), <anonymous>:544:10)
    at ReactCompositeComponentMixin.updateComponent (eval at <anonymous> (http://localhost:3000/app.js?1451913362157:2862:3), <anonymous>:473:12)
    at wrapper [as updateComponent] (eval at <anonymous> (http://localhost:3000/app.js?1451913362157:717:3), <anonymous>:66:21)
    at ReactCompositeComponentMixin.performUpdateIfNecessary (eval at <anonymous> (http://localhost:3000/app.js?1451913362157:2862:3), <anonymous>:421:12) 

It does work when I call setState directly without the setTimeout or in my actual case a callback function from a Firebase call.

It always works in Firefox.

I'm using "react": "^0.14.0", and "babel": "^5.8.29",.

Ad

Answer

You shouldn't asynchronously set state in componentWillMount, use componentDidMount for that instead. Actually you're not supposed to call setState at all before the component is mounted (so therefore doing it in componentWillMount is risky even in an async callback).

https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount

If you want to integrate with other JavaScript frameworks, set timers using setTimeout or setInterval, or send AJAX requests, perform those operations in this method.

You can read a more in depth reason here: https://stackoverflow.com/a/29995104/414062

Ad
source: stackoverflow.com
Ad