Rails 5 Redux React服务器端渲染为客户端提供JavaScript警告'用新的...替换React渲染的子级'

时间:2016-08-06 00:28:31

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

更新:问题孤立 - react-rails和npm版本的React不同 - 修复自己的答案

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

java -jar java-cup-11a.jar java_cup.Main yyy.cup

该网站似乎工作正常,但显然有些事情发生了:)

index.html.erb:

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.

components.js:

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

WeatherRoot.es6.js

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

WeatherContainer.es6

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>
    );
  }
}

页面渲染:

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>

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

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

基本上,节点从服务器端呈现的ID为“1”,并且

/**
 * 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;
}

使用此实现返回null:

ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID)

看起来id需要以a开头。通过?

为什么服务器端渲染的ID不以。?

开头

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

添加一些调试:

(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;
}

显示这些日志:

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

!!!!

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

2 个答案:

答案 0 :(得分:2)

好的,我发现了问题

通过添加控制台日志,我能够看到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中,我强制反应和反应到版本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'

现在两者都反应0.14.3

并且警告消失了

答案 1 :(得分:0)

尝试将WeatherRoot回复包装在<div>中,如下所示:

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