【问题标题】:Rails 5 Redux React Server Side Rendering gives client side JavaScript warning 'Replacing React-rendered children with a new...'Rails 5 Redux React 服务器端渲染给客户端 JavaScript 警告“用新的替换 React 渲染的子项......”
【发布时间】:2016-08-06 00:28:30
【问题描述】:

更新:问题已隔离 - React 的 react-rails 和 npm 版本不同 - 在下面自己的答案中修复

在 rails 5 上使用 rails-react 并收到此警告:

Replacing React-rendered children with a new root component. If you
intended to update the children of this node, you should instead have
the existing children update their state and render the new
components instead of calling ReactDOM.render.

该网站似乎运行良好,但显然有些问题:)

index.html.erb:

<div class="item">
  <%= react_component('WeatherRoot', {}, { :prerender => true } ) %>
</div>

components.js:

window.React = require('react');
window.ReactDOM = require('react-dom');
window.WeatherRoot  = require('./components/containers/WeatherRoot.es6').default;

WeatherRoot.es6.js

import React, { Component } from 'react';
import { render } from 'react-dom'
import { Provider } from 'react-redux';
import WeatherContainer from './WeatherContainer.es6';
import configureStore from '../store/configureStore.es6';

import {fetchWeather} from '../actions/weather.es6';

const store = configureStore();

// Request Data as Early as Possible
store.dispatch(fetchWeather());

export default class WeatherRoot extends Component {
  render() {
    return (
      <Provider store={store}>
        <WeatherContainer />
      </Provider>
    );
  }
}

WeatherContainer.es6

import { connect } from 'react-redux'
import Weather from '../components/Weather.es6';


export function WeatherContainerImpl(props){
    return (<div>HELLO</div>);
}

const mapStateToProps = (state, ownProps) => {
  return {
    weather: state.weather.data
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    dispatch
  }
}

const WeatherContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(WeatherContainerImpl);

export default WeatherContainer;

页面渲染:

<div data-react-class="WeatherRoot" data-react-props="{}">
  <div data-reactroot="" data-reactid="1" data-react-checksum="-951512882">HELLO</div>
</div>

替换为客户端渲染:

<div data-react-class="WeatherRoot" data-react-props="{}">
  <div data-reactid=".0">HELLO</div>
</div>

调试 ReactMount.js 显示此方法返回 true 作为警告的来源:

/**
 * True if the supplied DOM node has a direct React-rendered child that is
 * not a React root element. Useful for warning in `render`,
 * `unmountComponentAtNode`, etc.
 *
 * @param {?DOMElement} node The candidate DOM node.
 * @return {boolean} True if the DOM element contains a direct child that was
 * rendered by React but is not a root element.
 * @internal
 */
function hasNonRootReactChild(node) {
  var reactRootID = getReactRootID(node);
  return reactRootID ? reactRootID !== ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID) : false;
}

从服务器端渲染和

ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID)

使用此实现返回 null:

(id) {
  if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
    var index = id.indexOf(SEPARATOR, 1);
    return index > -1 ? id.substr(0, index) : id;
  }
  return null;
}

看起来 id 需要以 .通过?

为什么服务器端渲染的 id 不以 .? 开头?

也许我有不同版本的反应?但两者看起来都像 14.8

添加一些调试:

export function WeatherContainer(props){
  console.log("WeatherContainer", React.version)
  return (<div>HELLO</div>);
}

显示这些日志:

WeatherContainer 15.2.1
WeatherContainer 0.14.8

!!!!

现在如何弄清楚我是如何获得两个版本的?

【问题讨论】:

  • 我刚刚阅读了整个问题,发现您有两个不同的反应版本?我会先解决这个问题,我猜 react-rails 附带一个版本,而你使用的是不同的版本。
  • 是的,我花了好几个小时才弄清楚,我正在添加注释,因为抱歉会更新标题

标签: javascript ruby-on-rails reactjs redux connect


【解决方案1】:

好的,我找到了问题

通过添加控制台日志,我可以看到 React 的服务器版本与客户端版本不同

export function WeatherContainer(props){
  console.log("WeatherContainer", React.version)
  return (<div>HELLO</div>);  
}

给:

WeatherContainer 15.2.1
WeatherContainer 0.14.8

注意:由于 application.rb 中的 replay_console 设置,控制台日志在客户端可见

config.react.server_renderer_options = {
    files: ["react-server.js", "components.js"], # files to load for prerendering
    replay_console: true,                 # if true, console.* will be replayed client-side
    }

react-rails-1.8.1 捆绑包反应 15.2.1

所以在 package.json 我强制 react 和 react-dom 到 0.14.3 版本

npm install -S react@0.14.3
npm install -S react-dom@0.14.3

在 Gemfile 中,我用

强制 react-rails 到 1.5.0
gem 'react-rails', '1.5'

现在两者都是 react 0.14.3

警告消失了

【讨论】:

    【解决方案2】:

    尝试将您的 WeatherRoot 响应包装在 &lt;div&gt; 中,如下所示:

    export default class WeatherRoot extends Component {
      render() {
        return (
          <Provider store={store}>
            <div><WeatherContainer /></div>
          </Provider>
        );
      }
    }
    

    【讨论】:

    • 嗨,杰克!我做了那个改变,但仍然有同样的问题,不过谢谢你的想法!服务器端:
      HELLO
      客户端:
      你好
    猜你喜欢
    • 2019-08-07
    • 1970-01-01
    • 2016-03-26
    • 2015-05-07
    • 1970-01-01
    • 1970-01-01
    • 2018-01-05
    • 2017-07-20
    • 1970-01-01
    相关资源
    最近更新 更多