[React Error]: Target container is not a DOM element
出现此错误的原因是我将webpack生成的js文件放在了head,此时DOM还没有建立完毕,因此出现 not a DOM element 的错误,所以将js文件放在HTML底部就可以了。
注意,react声明组件时,第一个字母必须大写。
当JSX包含多行代码时,将它们包含在小括号中。
/// bad
render() {
return <MyComponent className="long body" foo="bar">
<MyChild />
</MyComponent>;
}
// good
render() {
return (
<MyComponent className="long body" foo="bar">
<MyChild />
</MyComponent>
);
}
// good, when single line
render() {
const body = <div>hello</div>;
return <MyComponent>{body}</MyComponent>;
}
Declaration(声明)
不要使用displayName来命名组件,而使用引用。
// bad
export default React.createClass({
displayName: 'ReservationCard',
// stuff goes here
});
// good
export default class ReservationCard extends React.Component {
}
以下参考 http://react-china.org/t/react-js/10144
同构方案
这里我们采用React技术体系做同构,由于React本身的设计特点,它是以Virtual DOM的形式保存在内存中,这是服务端渲染的前提。
对于客户端,通过调用ReactDOM.render方法把Virtual DOM转换成真实DOM最后渲染到界面。
import { render } from 'react-dom'
import App from './App'
render(<App />, document.getElementById('root'))
对于服务端,通过调用ReactDOMServer.renderToString方法把Virtual DOM转换成HTML字符串返回给客户端,从而达到服务端渲染的目的。
import { renderToString } from 'react-dom/server'
import App from './App'
async function(ctx) {
await ctx.render('index', {
root: renderToString(<App />)
})
}
状态管理方案
我们选择Redux来管理React组件的非私有组件状态,并配合社区中强大的中间件Devtools、Thunk、Promise等等来扩充应用。当进行服务端渲染时,创建store实例后,还必须把初始状态回传给客户端,客户端拿到初始状态后把它作为预加载状态来创建store实例,否则,客户端上生成的markup与服务端生成的markup不匹配,客户端将不得不再次加载数据,造成没必要的性能消耗。
服务端
import { renderToString } from 'react-dom/server'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import App from './App'
import rootReducer from './reducers'
const store = createStore(rootReducer)
async function(ctx) {
await ctx.render('index', {
root: renderToString(
<Provider store={store}>
<App />
</Provider>
),
state: store.getState()
})
}
HTML
<body>
<div id="root"><%- root %></div>
<script>
window.REDUX_STATE = <%- JSON.stringify(state) %>
</script>
</body>
客户端
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import App from './App'
import rootReducer from './reducers'
const store = createStore(rootReducer, window.REDUX_STATE)
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
要在HTML也中使用React有两种方法,一个是使用Webpack编译打包,另一个是使用网页直接添加React相关js文件
用webpack来编译、打包React组件。并在一个index.html的页面中使用该代码。具体的准备步骤可以看这里。最后打包到一个叫做bundle.js的文件中。HTML页面看起来是这样的:
<html>
<head>
<meta charset="utf-8">
<title>Add style to React</title>
</head>
<body>
<div id="content" />
<script src="public/bundle.js" type="text/javascript"></script>
<span style="float:center">Yo!</span>
</body>
</html>
也可以在网页中直接使用React的js代码。
<html>
<head>
<meta charset="utf-8">
<title>Add style to React</title>
<!-- 所需要引入的React及相关js -->
<script src="https://npmcdn.com/react@15.3.1/dist/react.js"></script>
<script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.js"></script>
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
<!-- end -->
</head>
<body>
<div id="content" />
<!-- 我们自己的js -->
<script src="public/bundle.js" type="text/javascript"></script>
<span style="float:center">Yo!</span>
</body>
</html>
jquery文件可以不用添加,这里用jquery是用来请求服务器的,暂时用不到。
无论使用哪一种方式。最后在页面中使用的js都是bundle.js。如果用了webpack的方式,那么bundle.js就是由webpack便已打包生成的。如果用的第二种方法,那么bundle.js就是我们自己手动编写的js代码。