对客户端而言,最好通过node中间层 。而对于这个SSR项目而言,node开启的服务器本来就是一个中间层的角色,因而对于服务器端执行数据请求而言,就可以直接请求真正的后端接口啦 。
//actions.js//参数server表示当前请求是否发生在node服务端const getUrl = (server) => {return server ? 'xxxx(后端接口地址)' : '/api/sanyuan.json(node接口)';}//这个server参数是Home组件里面传过来的,//在componentDidMount中调用这个action时传入false,//在loadData函数中调用时传入true, 这里就不贴组件代码了export const getHomeList = (server) => {return dispatch => {return axios.get(getUrl(server)).then((res) => {const list = res.data.data;dispatch(changeList(list))})}}复制代码
在server/index.js应拿到前端的请求做转发,这里是直接用proxy形式来做,也可以用node单独向后端发送一次HTTP请求 。
//增加如下代码import proxy from 'express-http-proxy';//相当于拦截到了前端请求地址中的/api部分,然后换成另一个地址app.use('/api', proxy('http://xxxxxx(服务端地址)', {proxyReqPathResolver: function(req) {return '/api'+req.url;}}));复制代码
三、请求代码优化其实请求的代码还是有优化的余地的,仔细想想,上面的server参数其实是不用传递的 。
现在我们利用axios的instance和thunk里面的withExtraArgument来做一些封装 。
//新建server/request.jsimport axios from 'axios'const instance = axios.create({baseURL: 'http://xxxxxx(服务端地址)'})export default instance//新建client/request.jsimport axios from 'axios'const instance = axios.create({//即当前路径的node服务baseURL: '/'})export default instance复制代码
然后对全局下store的代码做一个微调:
import {createStore, applyMiddleware, combineReducers} from 'redux';import thunk from 'redux-thunk';import { reducer as homeReducer } from '../containers/Home/store';import clientAxios from '../client/request';import serverAxios from '../server/request';const reducer = combineReducers({home: homeReducer})export const getStore = () => {//让thunk中间件带上serverAxiosreturn createStore(reducer, applyMiddleware(thunk.withExtraArgument(serverAxios)));}export const getClientStore = () => {const defaultState = window.context ? window.context.state : {};//让thunk中间件带上clientAxiosreturn createStore(reducer, defaultState, applyMiddleware(thunk.withExtraArgument(clientAxios)));}复制代码
现在Home组件中请求数据的action无需传参,actions.js中的请求代码如下:
export const getHomeList = () => {//返回函数中的默认第三个参数是withExtraArgument传进来的axios实例return (dispatch, getState, axiosInstance) => {return axiosInstance.get('/api/sanyuan.json').then((res) => {const list = res.data.data;console.log(res)dispatch(changeList(list))})}}复制代码
至此,代码优化就做的差不多了,这种代码封装的技巧其实可以用在其他的项目当中,其实还是比较优雅的 。
part6: 多级路由渲染(renderRoutes)现在将routes.js的内容改变如下:
import Home from './containers/Home';import Login from './containers/Login';import App from './App'//这里出现了多级路由export default [{path: '/',component: App,routes: [{path: "/",component: Home,exact: true,loadData: Home.loadData,key: 'home',},{path: '/login',component: Login,exact: true,key: 'login',}]}]复制代码
现在的需求是让页面公用一个Header组件,App组件编写如下:
import React from 'react';import Header from './components/Header';constApp = (props) => {console.log(props.route)return (<div><Header></Header></div>)}export default App;复制代码
对于多级路由的渲染,需要服务端和客户端各执行一次 。因此编写的JSX代码都应有所实现:
//routes是指routes.js中返回的数组//服务端:<Provider store={store}><StaticRouter location={req.path} ><div>{renderRoutes(routes)}</div></StaticRouter></Provider>//客户端:<Provider store={getClientStore()}><BrowserRouter><div>{renderRoutes(routes)}</div></BrowserRouter></Provider>复制代码
这里都用到了renderRoutes方法,其实它的工作非常简单,就是根据url渲染一层路由的组件(这里渲染的是App组件),然后将下一层的路由通过props传给目前的App组件,依次循环 。
那么,在App组件就能通过props.route.routes拿到下一层路由进行渲染:
import React from 'react';import Header from './components/Header';//增加renderRoutes方法import { renderRoutes } from 'react-router-config';constApp = (props) => {console.log(props.route)return (<div><Header></Header><!--拿到Login和Home组件的路由-->{renderRoutes(props.route.routes)}</div>)}export default App;复制代码
推荐阅读
- 吃什么补血 中医教你补气血
- 教你煮饺子的方法,煮出的饺子更好吃 怎么煮饺子
- 教你怎样调配花草茶,润肤花草茶
- 从草本植物角度科学的认识百合花茶,四大步骤教你如何简易而快速的冲泡百合花茶
- 手把手教你进行pip换源,让你的Python库下载嗖嗖的
- 今日头条如何发文才有收益?新人朋友请看过来,教你一步步操作
- 教你安全配花茶,花茶的感官鉴赏
- 百合花茶搭配,四大步骤教你如何简易而快速的冲泡百合花茶
- 13个护发误区大扫盲,教你掌握正确洗护方法
- 黑苦荞茶什么牌子纯正,四大步骤教你如何简易而快速的冲泡百合花茶