Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize isomorphic template in react

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)05/31 Report--

The knowledge of this article "how to achieve isomorphism template in react" is not understood by most people, so the editor summarizes the following content, detailed content, clear steps, and has a certain reference value. I hope you can get something after reading this article. Let's take a look at this "how to achieve isomorphism template in react" article.

TODO List

Data: how to keep the status of front and rear applications consistent

Routing: the matching scheme of the route between the server and the client

Code: isomorphism, where to share and where to differentiate

Static resources: how to introduce css/ pictures and so on to the server

Ssr straight-out resources: how the server matches css/chunks resources when rendering routing pages

Packaging: how to write their webpack configuration files on the server side and the browser side

SEO: head header processing scheme

The basis of isomorphism

For a normal web page to run, it is necessary to generate dom, and after the dom tree loaded, js binds the related dom events to listen to the interaction of the page. The server does not have an dom execution environment, so all server renderings actually return a static text filled with the initial data. In react, in addition to the commonly used render method used to generate dom, the renderToString,renderToStaticMarkup method is also provided to generate strings. Due to the existence of VitualDOM, the combination of these methods can generate ordinary strings like previous string templates and return them to the client to take over, followed by event-related binding. The latest React v16 + uses hydrate and ssr, which allows the client to render the server VitualDOM and reuse it. After loading the js, the client does not redo it, reducing the overhead and avoiding the splash screen experience brought by the browser when rebrushing the dom. On the other hand, the components of react are written as usual when writing spa, and the front and back ends are shared. The only difference is that the rendering method of the portal has been changed, and the client will mount dom.

/ / clinet.jsReactDom.hydrate (, document.getElementById ('app')) / / server.jsconst html = ReactDom.renderToString ()

Flow chart of website operation after isomorphism

Embezzling a picture from the front end of Ali. At first glance, the difference between ssr and csr is that the 23-45 html mode simply rudely returns a blank html page, and then loads the data to fill the page in 11. Before that, the page was blank. On the other hand, ssr will get the initial data of the routing page in advance according to the routing information, and when it returns to the page, it already has the preliminary content, which is not blank, and is also convenient for search engines to include.

Route matching

There should be no need to worry about matching routes on the browser side or following spa. I skipped it.

The routing of the server needs to pay attention to, one is the matching of the routes (such as koa-router) of the back-end service, and the other is the matching of the react-router routing table after matching to the react application.

Server routing can be distinguished from api interface by / react prefix. This route matching method even enables server rendering to support template rendering of old projects such as ejs, and can be upgraded step by step in terms of system upgrade.

/ / app.js file (backend entry) import reactController from'. / controllers/react-controller'// API routing app.use (apiController.routes ()) / / ejs page routing app.use (ejsController.routes ()) / / react page routing app.use (reactController.routes ()) / / react-controller.js file import Router from 'koa-router'const router = new Router ({prefix:' / react'}) router.all ('/', async (ctx) Next) = > {const html = await render (ctx) ctx.body = html}) export default router

React-router is dedicated to the StaticRouter interface for ssr, which is called static routing. Admittedly, unlike the client, the route is the current request url corresponding to a network request, which is unique and immutable. After returning the ssr straight-out page, the page interaction changes the address bar. As long as you use the method provided by react-router, whether it is hash or history, it belongs to the work of react-router on the browser side, so it perfectly inherits the advantages of spa. Only when you click Enter in the input field will a new round of background requests be launched.

Import {StaticRouter} from 'react-router-dom' const App = () = > {return ()}

Application status data management

In the previous server rendering, the data that can be seen immediately after the client web page is downloaded is prepared in advance on the server and can be delayed for display, and the interactive logic of the data requested through ajax is placed in the js file loaded on the page.

Changed to react, in fact, the routine is the same. But the difference is:

In the traditional string template, the component template is separated from each other, and the data can be introduced separately and then assembled to form a html. In react's ssr, the page can only be render one-time through defaultValue and defaultProps, not rerender.

You can't write dead defaultValude, so you can only use props's data scheme. Prepare all the data for the entire application state in advance before executing the renderToString. Redux and mobx can be considered in the global data management scheme.

You need to prepare the initial rendering data, so get exactly which components the current address will render. React-router-config and react-router are of the same origin, and it is a tool that supports static routing table configuration and provides a matchRoutes method to obtain a matching route array.

Import {matchRoutes} from 'react-router-config'import loadable from' @ loadable/component'const Root = loadable ((props) = > import ('. / pages/Root')) const Index = loadable (() = > import (". / pages/Index")) const Home = loadable () = > import (". / pages/Home") const routes = [{path:'/', component: Root, routes: [{path:'/ index', component: Index,} {path:'/ home', component: Home, syncData () = > {} routes: []}] router.all ('/', async (url, next) = > {const branch = matchRoutes (routes, url)})

Of course, the most beautiful way to request the initial data interface of a component is to define it in the static methods of their respective class components, but only if the component cannot be loaded lazily, otherwise you can't get the component class or class static method. Many developers who use @ loadable/component (a code split solution) library mention issue many times, and the author explicitly cannot support it. It is absolutely impossible not to support lazy loading. So wronged by the code, define an asyncData method in the required route object.

Server side

/ / routes.js {path:'/ home', component: Home, asyncData (store, query) {const city = (query | |'). Split ('=') [1] let promise = store.dispatch (fetchCityListAndTemperature (city | | undefined)) let promise2 = store.dispatch (setRefetchFlag (false)) return Promise.all ([promise) Promise2]) return promise}} / / render.jsimport {matchRoutes} from 'react-router-config'import createStore from'.. / store/redux/index'const store = createStore () const branch = matchRoutes (routes, url) const promises = branch.map (({route}) = > {/ / traverse all matching routes Preload data return route.asyncData? Route.asyncData (store, query): Promise.resolve (null)}) / / complete the preloading data initialization of store await Promise.all (promises) / / get the latest storeconst preloadedState = store.getState () const App = (props) = > {return ()} / / after the data is ready, the whole render application const html = renderToString () / / Mount the preloaded data to return under `window` The client fetches return ${html} window.__PRELOADED_STATE__ = ${JSON.stringify (preloadedState)} by itself.

Client

In order to ensure the consistency of the application data on both sides, the client also initializes the store of redux once with the same data, and then generates the application. If the dom/ data of the two are inconsistent, causing the dom to be regenerated when the browser takes over, the console will output error messages in the development mode, and the development experience is perfect. The subsequent ajax data is executed in componentDidMount and events, and the server-side logic is naturally stripped.

/ / get the initialization data provided by the server const preloadedState = window.__PRELOADED_STATE__ | | undefineddelete window.__PRELOADED_STATE__// client store initialization const store = createStore (preloadedState) const App = () = > {return ()} / / loadableReady is provided by @ loadabel/component and is used in code split mode using loadableReady (). Then () = > {ReactDom.hydrate (, document.getElementById ('app')}))

The interface client called by the server must also have. This raises the question of how to avoid duplicate requests. We know that the componentDidMount method is executed only once, and if the data already requested by the server has an identity, it can be used to determine whether a new request needs to be initiated by the client. Note that the identity is reset after the judgment is completed.

Import {connect} from 'react-redux'@connect (state = > ({refetchFlag: state.weather.refetchFlag, quality: state.weather.quality}), dispatch = > ({fetchCityListAndQuality: () = > dispatch (fetchCityListAndQuality ()), setRefetchFlag: () = > dispatch (setRefetchFlag (true))}) export default class Quality extends Component {componentDidMount () {const {location: {search}, refetchFlag, fetchCityListAndQuality, setRefetchFlag} = this.props const {location: city} = queryString.parse (search) refetchFlag? FetchCityListAndQuality (city | | undefined): setRefetchFlag ()}}

Packaging scheme

Client packaging

What I want to say is "business as usual". Because spa is still running on the browser side. For entry-level details, see github. As for how to configure it to be pleasing to the eye and easy to use, show your skills according to the requirements of the project.

Server-side packaging

Similarities and differences between client and client:

Same as:

Bable is required to be compatible with different versions of js syntax

Webpack v4+/babel V7 +... It smells good.

... Leave blank

Different:

The import files are different and the export documents are different.

Here, you can not only use the entire server entry app.js as the packaging entry, but also take the starting point file of react routing as the packaging entry, configure the output to umd module, and then go to require by app.js. Take the latter as an example (the advantage is that when upgrading the renovation project, it is convenient to minimize the impact on the original system, to troubleshoot problems, and to debug breakpoints):

/ / webpack.server.jsconst webpackConfig = {entry: {server:'. / src/server/index.js'}, output: {path: path.resolve (_ _ dirname, 'build'), filename:' [name] .js', libraryTarget: 'umd'}} / / app.jsconst reactKoaRouter = require ('. / build/server') .defaultapp.use (reactKoaRouter.routes ())

Css and image resources normally do not need to be handled by the server, how to bypass

Lazy, haven't started to study yet, take up a hole

Avoid being packaged by webpack when require is a module that comes with node

Const serverConfig = {... Target: 'node'}

How to avoid being packaged when require third-party modules

Const serverConfig = {... Externals: [require ('webpack-node-externals') ()]

Production environment code does not need to do obfuscation compression

... Leave blank

Collection of resources when the server goes straight out

When the server outputs html, you need to define css resources and js resources so that the client can take over and download them for use. If there is no pursuit, you can directly add all the client output files, violent and safe, simple and convenient. But the @ loadable/component library mentioned above, after realizing the lazy loading / code split function of the routing component, also provides a full set of services, supporting sets of webpack tools and ssr tools to help us collect resources.

/ / webpack.base.jsconst webpackConfig = {plugins: [..., new LoadablePlugin ()]} / / render.jsimport {ChunkExtractor} from'@ loadable/server'const App = () = > {return ()} const webStats = path.resolve (_ _ dirname,'.. / public/loadable-stats.json', / / this file is automatically generated by the webpack plug-in) const webExtractor = new ChunkExtractor ({entrypoints: ['client'] / for entry file name statsFile: webStats}) const jsx = webExtractor.collectChunks () const html = renderToString (jsx) const scriptTags = webExtractor.getScriptTags () const linkTags = webExtractor.getLinkTags () const styleTags = webExtractor.getStyleTags () const preloadedState = store.getState () const helmet = Helmet.renderStatic () return `${helmet.title.toString ()} ${helmet.meta.toString ()} ${linkTags} ${styleTags} ${html} window.STORE = 'love' Window.__PRELOADED_STATE__ = ${JSON.stringify (preloadedState)}; ${scriptTags} `

SEO information

It's already been revealed. A react- Helmet library is used. For specific usage, you can check the official repository, and the information can be written directly on the component, and finally promoted to the head header according to priority.

The above is about the content of this article on "how to achieve isomorphic templates in react". I believe we all have a certain understanding. I hope the content shared by the editor will be helpful to you. If you want to know more about the relevant knowledge, please follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report