Detailed Reactive Rendering of the React Project (KOA2 ​​+ WebPack3.11)

because of the need to page SEO, and before the renovation project should React to render the service side, after some investigation and research, access to a wealth of Internet data. Successfully stepped pit.

Selection idea: implement server-side rendering, React want to use the latest version, and not the existing wording of big changes, if intends to start rendering server, it is recommended to write directly NEXT framework

LOCATION: https: //github.com/wlx200510/react_koa_ssr

Selection of scaffolding: webpack3.11.0 + react Router4 + Redux + koa2 + React16 + Node8. x

the main experience: React knowledge of the more familiar, successful expansion of their technical field of server technology has accumulated

on the actual project

Precautions: use framework the former must confirm that the current webpack version 3.x Node is 8.x or higher, preferably with React readers in more than three months, and practical project experience React

project catalog description

  ├── assets│ └── index.css // placed some global resource files can be js pictures ├── config│ ├── webpack.config. dev.js development environment webpack packaged set │ └── webpack.config.prod.js production environment webpack packaged set ├── package.json├── README.md├── server server side rendering files, if not very understanding , the proposed reference [KOA tutorial] (http://wlxadyl.cn/2018/02/11/koa-learn/) │ ├── app.js│ ├── clientRouter.js // In this file contains logic to match the server routing to React routes │ ├─ i i └└ │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ App This folder is mainly used to place a browser and Server Universal Logic │ ├─ ConfigureStore.js // REDUX-THUNK Settings │ ├─- createapp.js // Different Router mode │ ├─- ─ │ │ └───Router │ │ │ ├─- ─ ─ INDEX.JS │ └── Routes.js // Route Profile! Important ├─- Assets │ ├── CSS placed some public style files │ │ ├─ _ _ _base.scss // Many projects will be used in the initialization CSS │ │ ─ Idex.scss │ │ └── my.scss │ └ - ─ IMG ├─ Components Place some public components │ ├─FloatDownloadBTN Public Components Sample Writings │ │ ─FloatDownloadBtn.js │ │ ── FLOATDOWNLOADBTN.SCSS │ │ └─ ─ ─ ─ ─ ─. │ ├ ─ Loading.js │ └──Model.js Function Components Writings │ ├─── Favicon.ico ├─- Index.ejs // Rendering Template If the item is required, you can put some public files in- ─ ─ index. JS // includes thermal update logic ├ - Pages Page Component Folders │ ├── Home │ │ ├─- Components // Used to place page components, main logic │ │ │ └─Homepage.js │ │ ├─ - Containers // Use connection to use ConnectPackaged high-order components injection global state data │ │ │ └─HomeContainer.js │ │ ─Ix.js // Page Route Profile Note Thunk Attribute │ │ └─ ─ │ │ │ └──.. │ │ │ └─ ─X.js / / Page reducer here exposed to the Store unified handle note │ └ --- USER │ ├─ Components │ │ └── Userpage.js │ ├─- Containers │ │ └── UserContainer.js │ └─ ─ ─ dx. JS └─- store ├─- ActionS // Each Action storage │ ├─Home.js │ └ --- thunk.js ├─ constants.js // Each Action Name Collection Office Preventions - ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ INDEX.JS / / All reducer in each page is unified here Combine Process  

Construction Items of Project

    Local development uses WebPack-Dev-Server to achieve hot updates, the basic process is similar to the previous development, still browser-side rendering, so take into account a set of logic, two rendering environments.
  1. After the current terminal page rendering is completed, its Router jump will not request the server, thereby reducing the server pressure, thus the input method of the page is also two, but also considering the route in two rendering environments. Sybody problem.
  2. Production environment To use KOA to do backend servers, implement on-demand loading, get data on the server, and rendering the entire HTML, using the React16’s latest capabilities to merge the entire state tree, implement server rendering.
introduce local development

to view the file locally developed mainly related to the index.js files in the src directory, determine the current operating environment, the API used only module.hot in the development environment achieved when the reducer changed page rendering update notification, pay attention to hydrate the methods, this method is a special rendering API for the new version of the server v16, which implements the server-side rendering to render method on the basis of the content of the the maximum possible reuse, the process to achieve a static to a dynamic DOM of NODES. Essence is determined checksum process instead of the labeled version v15, so that the reuse process more efficient and elegant.

const renderApp = () => {let application = createApp ({store, history}); hydrate (application, document.getElementById ( ‘root’));} window.main = () => {Loadable.preloadReady () then (() => {renderApp ()});.}; if (process.env.NODE_ENV === ‘development’) {if (module.hot ) {module.hot.accept ( ‘./ store / reducers / index.js’, () => {let newReducer = require ( ‘./ store / reducers / index.js’); store.replaceReducer (newReducer)} ) module.hot.accept ( ‘./ app / index.js’, () => {let {createApp} = require ( ‘./ app / index.js’); let newReducer= Require ( ‘./ store / reducers / index.js’); store.replaceReducer (newReducer) let application = createApp ({store, history}); hydrate (application, document.getElementById ( ‘root’));}) }}
   Note that the definition of this function of Window.main, combined with index.ejs, know that this function is triggered after all scripts are loaded, and it is React-loadable. The writing, lazy loading for the page, the writing of the packets to the page should be combined with routing settings, there is a general impression. It should be noted that the three ways of this file in this file are common to the browser and the server, which is mainly to say that this part of the idea. 

Next, the following SRC / APP directory, INDEX.JS exposes three methods, three methods involved in this service End and browser development will be used, this part is primarily talked about the code ideas of the Router file and the process of the CREATEAPP.JS file on the route. Here is a key point to implement two-end route mutual progress. The routes.js under the Router folder is the routing profile, which is introduced to the routing configuration under each page, synthesizing a configuration array, can flexibly control the page on the line through this configuration. InDex.js under the directory is the standard writing method of the Routerv4. By traversing the configuration array configuration, ConnecTrouter is a component used to merge ROUTER, notice that History is incorporated into the createApp.js file. Do separate processing. First, look at several configuration items in the Route component, it is worth noting that the Thunk property is, this is the rear end acquisitionThe key step of the rendering of the data is that this property implements the lifecycle hook similar to the components in next, and the rest of the property can be found in the relevant React-Router documentation, here is not described here.


Import Routesconfig from ‘./routes’; Const Routers = ({History}) => (

{Routesconfig.map (route =>

) Export Default Routers;
   You can find that the code inside the CreateApp.js in the app directory can be found. This framework is targeted. Different work environments have different processing, only use the loadable.capture method in the production environment to implement lazy loading, dynamically introduce the packed JS files corresponding to different pages. Here you still have to look at the write method of the routing profile in the component, as an example of Index.js under the HOME page. Note / * WebPackChunkName: 'Home' * / String Character, essences to specify the JS file name corresponding to the package, so this comment also needs to be modified for different pages, avoid packaging together. Loading This configuration item will only take effect in the development environment. This actual project development if the page is displayed before the page is loaded. This component is not required to delete this component. 
Import {homethunk} from '../../store/Afficnesss/thunk';const loadingableHome = loadingable ({Loader: () => import (/ * WebPackChunkname: 'Home' * / '. / Containers / HomeContainer.js'), loading: Loading,}); const HomeRouter = {path: '/', exact: true, component: LoadableHome, thunk: homeThunk // server performs rendering and opens the action, for acquiring page rendering data required} export default HomeRouter

here say one more thing, sometimes we have to transform the page file of the project, there are arguments from window.location code to get inside, transforming when rendering to the server to remove all, or is to be used in the life cycle after the render in. And page-level components have been injected into the relevant routing information can be obtained inside the URL parameters this.props.location. This project using a BrowserRouter, if HashRouter contains parameters may be slightly different, access to the actual situation.

The React16 server-side rendering API description:
 browser is implanted ConnectedRouter the history is: import createHistory from 'history / createBrowserHistory'   history server used for import createHistory 
server from ‘history / createMemoryHistory’

render

here does not involve some basic knowledge of koa2 If not familiar with the framework for koa2 can refer to my other blog post. Here is a look at both the server code server folder. The first is simple app.js guarantee for each connection returns a new instance of the server side, it is critical for single-threaded js languageThoughts. It is necessary to focus on this file that is ClientRouter.js, combined with the /src/app/configurestore.js, which works together to understand the server rendering data acquisition process and React rendering mechanism.
  1. / * configurestore.js * / Import {createstore, ApplyMiddleWare, Compose} from “redux”; import thunkmiddleware from “redux-tunk”; import createhistory from ‘History / createMemoryHistory ‘; import {routerReducer, routerMiddleware} from’ react-router-redux’import rootReducer from ‘../store/reducers/index.js’;const routerReducers = routerMiddleware (createHistory ()); // const composeEnhancers = process route .env.NODE_ENV == ‘development’ window .__ REDUX_DEVTOOLS_EXTENSION_COMPOSE__: compose; const middleware = [thunkMiddleware, routerReducers]; // reducer is injected into the route, routing information may be obtained directly from the reducer in the let configureStore = (initialState) => createStore? (Rootreducer, InitialState, Complynhancers (Applymiddleware..middleware))); Export Default configurestore;
  2. Window .__ rX_devtools_extension_compose__ This variable is the developer tool in the browser, it is recommended to install when developing React-Redux applications. Otherwise there will be an error prompt. Most of this is the sample code of the Redux-Thunk. If you don’t understand the official documentation of the Redux-Thunk, you should pay attention to the initialState parameters of Configurestore, this rendering specific idea Yes: In the server judgment routing Thunk method, if there is an execution of this acquisition data logic, this is a blocking process, which can be used as synchronization, after the acquisition is in the global state, injecting Window .__ initial_state___________________ This global variable, after the HTML is loaded, this variable assigns the global state of the existing data as the initState to the React application, and then the browser’s JS is loaded after the DOM and the existing DOM and the initial initstate. Start, in the life cycle after merged into the render, there is already possible to get the rendered required data from this.props in the ComponentDidMount.
But also considers that the page switching is also possible to perform jump at the front end. At this time, the application as a React does not trigger a request for the backend, so there is no data in the life cycle of ComponentDidMount, In order to solve this problem, I recommend calling the Action trigger function sent in the PROPS in this lifecycle, but a layer of logical judgment is performed inside the action, avoiding a repeated request, and requesting data in the actual project tends to have an identifier ID. You can store this ID into the Store, then you can return to the check before returning, avoid repeated sending AJAX requests, specifically watching Store / ActLogic processing in IONS / home.js`

Import {add, get_home_info} from ‘../constants’Export const address => ({type: add, count,}) Export Const gethomfo = (sendID = 1) => async (dispatch, getState) => {let {name, age, id} = getState (). HOMEREDUCER.HOMEINFO; if (id === sendid) {Return // is a request The ID and the identification ID of the existing data are compared to avoid repeated acquisition data. } console.log (‘footer’inclus (‘ foo ‘)) AWAIT new promise (resolve => {let homeInfo = {name:’ WD2010 ‘, age:’ 25 ‘, id: sendid} console.log (‘ – ———- Request gethomeInfo ‘) setTimeout (() => resolve (homeInfo), 1000)}). Then (HOMEINFO => {Dispatch ({type: get_home_info, data: {homeinfo}}) })}}}}}}

Note that async / await is written here, which involves the server KOA2 to use this to do data requests, so it is necessary to returns an Async function, this is not familiar. Students suggest that the ES7 is known, mainly how Async is in line with Promise to renovate asynchronous process, and if it involves KoA2 server work, more for the Async function, this is also the project requires the Node version of 8.x or more. Reason, can be straight from 8Use these two keywords.

However, in the specific project, it is often involved in the injection problem of some server parameters, but this piece is very different depending on the demand of different projects, and does not belong to the part of this React server, no The law is unified, if it is a company project to use the demand consultation to reward, add my WeChat discussion.
  With the home page as an example, the rendering process  
In order to facilitate everyone to understand, I tailored the overall process of the data stream as an example, look at the ideas:


The server receives the request, and the corresponding routing configuration is found.

determines the route existence THUNK method, at this time, the exposure of the Store / ActionS / Thunk.js is executed. Function

The asynchronous acquisition data is injected into the global state, at which time the Dispatch distribution is not effective
 The html code to be output will be obtained after the data is obtained. WINDOW .__ITIAL_STATE__ This global variable, as INITSTATE   window .__ initial_state__ will incorporate the global State before the React Lifecycle, at this time, Render is found to be generated, and the render will not trigger again, and data Synchronization 

The server is directly out of HTML

The basic process has been introduced, as for some of the REDUCER functions Writing, as well as the location of the ActionS is to organize some of the analysis of the online analysis, seeing the benevolence, this is just in line with your own understanding and helps the team development. If you meet the reader background set in the article, I believe that this article tells you enough to light your own server rendering technology. If you don’t have a little less about React, you can refer to here to add some of the basics of some React

The above is all the content of this article, I hope to help everyone, I hope everyone will support Tumi Cloud.

© Copyright Notice
THE END
Just support it if you like
like0
share
comment Grab the couch

Please log in to comment