项目地址:git@github.com:longlongdan/Reactssr.git
- 服务端渲染之后,客户端会再次渲染,因为我们的客户端创建的store为空。解决办法:在服务端渲染的时候将获取到的数据赋值一个全局变量(注水),客户端创建的store以这个变量的值作为初始值(脱水)。
const Store = createStore(Rducer,window.info,applyMiddleware(thunk));
- 中间层代理转发,我们的浏览器端渲染之前是直接发送'http://47.95.113.63/ssr/api/news.json?secret=PP87ANTIPIRATE'远程服务器上取数据,现在我们需要,让他请求我们本地的node服务器,node服务器去代理这个请求带远程服务器上面,
//浏览器端发送代码 相当于请求的是localhost:3000/api/news... return fetch('/api/news.json?secret=PP87ANTIPIRATE') .then((res)=>{ return res.json(); })
//后端proxy代理 const proxy = require('http-proxy-middleware'); app.use('/api',proxy({ target: 'http://47.95.113.63/ssr' }))
- (了解axios中instanse的写法 interceptors 概念)我们使用的fetch,可以自己对fetch方法进行封装
//客户端 const baseUrl = ''; const fetchClient = (url) => { return fetch(baseUrl+url); } export default fetchClient;
//服务端 import fetch from 'node-fetch' const baseUrl = 'http://47.95.113.63/ssr'; const fetchServer = (url) => { return fetch(baseUrl+url); } export default fetchServer;
- thunk的withExtraArgument的用法,为我们中间件调用的时候传入额外的参数。fetch方法封装好之后我们需要判断代码执行在浏览器端还是服务端,解决办法是通过thunk中间件在创建store的时候将封装的fetch方法传进来。
//客户端 const Store = createStore(Rducer,window.info,applyMiddleware(thunk.withExtraArgument(fetchClient))); //服务端 const Store = createStore(Reducer, applyMiddleware(thunk.withExtraArgument(fetchServer)));
发送请求的代码,会接受第三个参数,就是我们自定义的额外参数
export const getHomeList = (dispatch, getState, fetch) => { return fetch('/api/news.json?secret=PP87ANTIPIRATE') .then((res)=>{ return res.json(); }) }
- rnderRoutes对多级路由的区别 renderRoutes方法会去帮我们渲染一级路由,然后将下一层的routes(二级路由)带进一级路由所匹配到的组件之中,我们需要在一级路由匹配的组件里面再次调用renderRoutes方法对props.route.routes进行渲染
//router.js export default [ { path: '/', component: Header, //共用的header头部 routes: [ { path: '/', exact: true, getData: Home.getData, component: Home, }, { path: '/Login', getData: ()=>{console.log('getData login')}, component: Login } ] } ]
在header里面需要继续渲染二级路由
const Header = (props) => { return ( <div> <Link to='/'>Home</Link> <br/> <Link to='/Login'>Login</Link> { renderRoutes(props.route.routes) } </div> ) }