최대한 빠른 렌더링 시간과 빠른 페이지 응답 속도가 필요할 때 서버사이드 렌더링을 사용하겠습니다. 이 글에서는 주로 React 서버사이드 렌더링을 소개합니다
1. 머리말
왜 서버사이드 렌더링이 필요한가요? 서버 측 렌더링은 어떤 상황에서 수행됩니까? 저자는 렌더링 시간이 최대한 빨라야 하고 페이지 응답 속도가 빨라야 할 때(장점) 서버 렌더링이 사용되며, 페이지는 "요청 시" - "첫 번째 로드/첫 화면"으로 렌더링되어야 한다고 믿습니다. ". 서버 측 렌더링의 장점은 중간 계층(노드)이 클라이언트에 대한 초기 데이터를 요청하고 노드가 페이지를 렌더링한다는 것입니다. 클라이언트 측 렌더링과 서버 측 렌더링의 차이점은 무엇입니까? 서버사이드 렌더링은 얼마나 빠른가요?
2. 이유 및 아이디어
클라이언트 측 렌더링 경로: 1. html 요청 -> 2. 서버는 html을 반환합니다. 3. 브라우저는 html로 js/css 파일을 다운로드합니다. -> 4. js 파일 다운로드가 완료될 때까지 기다립니다. -> 5. js가 로드되고 초기화될 때까지 기다립니다. -> 백엔드(ajax/fetch) -> 7. 백엔드 데이터가 반환될 때까지 기다립니다. -> 8. React-dom(클라이언트)은 데이터를 처음부터 응답 페이지로 렌더링하여 완료합니다.
서버 측 렌더링 경로: 2. html 요청 -> 2. 서버에서 데이터 요청(인트라넷 요청이 빠름) -> 3. 서버 초기 렌더링(서버 성능이 좋고 빠름) -> 4. 서버가 올바른 콘텐츠로 페이지를 반환합니다. .클라이언트가 js/css 파일을 요청합니다. -> 6. js 파일이 다운로드될 때까지 기다립니다. -> 7. js가 로드되고 초기화될 때까지 기다립니다. -> 8. React-dom(클라이언트)이 렌더링을 완료합니다. 나머지 부분(작은 콘텐츠, 빠른 렌더링)
참고: 예 동일한 구성 요소에 대해 서버는 구성 요소가 완전한 수명 주기를 갖도록 하기 위해 "시각적" 부분(코드의 렌더링/구성 요소WillMount 부분)을 렌더링합니다. 그리고 이벤트 처리, 클라이언트는 이를 다시 렌더링해야 합니다. 즉, 서버 측 렌더링에서는 실제로 클라이언트가 2차 렌더링을 다시 수행해야 하지만 오버헤드는 거의 없습니다.
시간 소모 비교:
1. 데이터 요청: 클라이언트 대신 서버가 데이터를 요청하는데, 이는 "빠름"의 주요 이유 중 하나입니다. 서버는 인트라넷으로 요청을 하며, 데이터 응답 속도가 빠릅니다. 클라이언트는 서로 다른 네트워크 환경에서 데이터를 요청하는데, 외부 네트워크 http 요청에는 비용이 많이 들고 시간 차이가 발생합니다(주된 이유).
2. 단계: 서버는 먼저 데이터를 요청한 다음 "시각적" 부분을 렌더링하는 반면, 클라이언트는 js 코드가 다운로드되기를 기다리고 데이터 및 렌더링을 요청하기 전에 로딩이 완료됩니다. 즉, 서버 측 렌더링은 데이터를 요청하기 전에 js 코드가 다운로드될 때까지 기다릴 필요가 없으며 이미 콘텐츠가 있는 페이지를 반환합니다.
3. 렌더링 성능: 서버 성능이 클라이언트보다 높고 렌더링 속도도 더 빠릅니다(추측, 이 데이터는 알 수 없음).
4. 콘텐츠 렌더링: 서버 측 렌더링은 "시각적" 부분을 먼저 렌더링한 다음 부분 렌더링을 위해 클라이언트에 전달합니다. 클라이언트 측 렌더링은 처음부터 시작되며 전체 렌더링 단계가 필요합니다.
3. Notes 및 질문
0. 프로젝트는 무엇에 달려 있나요? 답변: 노드 측: express, React-dom/server, webpack. 프런트엔드: React, mobx(더 나은 redux), React-router, webpack
1. 프런트엔드/노드 엔드는 코드의 어떤 부분을 공유합니까? 답변: 노드/프론트엔드에는 자체 항목 파일인 server.js/client.js와 중간 레이어
// routes.js module.exports = ( <Route path="/" component={ IComponent } > <Route path="/todo" component={ AComponent }> </Route> </Route> )
routes.js가 있습니다. 2. 코드는 앞면과 뒷면으로 구성되어 있습니다. 각 플랫폼에서 공유한다면, 플랫폼마다 다른 코드를 어떻게 운용할 수 있나요? 답변: 웹팩을 통해.
// webpack.client.config.js plugins: [ new webpack.DefinePlugin({ 'isServer': false, 'isClient': true }) ] // webpack.server.config.js plugins: [ new webpack.DefinePlugin({ 'isServer': true, 'isClient': false }) ] // xxx.js if( isServer ) { ... }else { ... }
4를 추가하여 다양한 플랫폼용 webpack(babel)으로 공유 코드를 컴파일합니다. 답변: componentWillMount(node side) -> render(node side) -> 클라이언트 수명주기는 이전과 동일합니다
5. 데이터를 어떻게 처리하나요? 답변: 먼저 노드 측의 데이터를 기반으로 렌더링한 다음 페이지와 함께 데이터를 프런트 엔드로 반환합니다. 그런 다음 React는 데이터를 기반으로 렌더링 및 교정을 수행합니다(프론트 엔드와 백엔드의 렌더링 결과가 다음과 같은 경우). 일치하지 않으면 오류가 보고됩니다.) 구성요소는 componentWillMount
// 组件.js componentWillMount() { if( isClient ) { this.todoStore.todos = window.initTodos; } } // node端返回 ` <!doctype html> <html lang="utf-8"> <head> <script> window.initTodo = ${...}</script> </head> <body> ... </body> <script src="/static/vendor.js"></script> <script src="/static/client.bundle.js"></script>
6. 前端/node端“入口文件”通过webpack构建有什么不同?答:前端是为了解析JSX与es6代码(包括mobx的es6 decorator),node端除了以上,还需要加入babel-plugin-transform-runtime,是为了在node良好地运行es7 async / awatit
7. 如何保证node端能够先请求数据然后再渲染?答:es7的async / await语法
8. 前端的react-router路由与node端路由如何配合?node如何知道该路由是渲染哪个数据呢?答:前端是以前的react-router配置,node端是react-router的match/RouterContext// 共享文件routes.js
const routes = ( <Route path="/" component={ IComponent } > <Route path="/todo" component={ AComponent }> </Route> </Route> ) // 前端入口文件client.js render( <Router routes={ routes } history={ browserHistory } />, ele ) // node端入口文件server.js let app = express(); app.get('/todo', (req, res) => { match({ routes: routes, location: req.url }, async (err, redirect, props) => { // match会帮我们找到要渲染的组件链,注:上面一行使用了async语法,因此可以在render之前使用await运行拉取数据的代码 let html = renderToString(<RouterContext {...props} />) res.send( indexPage(html) ) } }) // node端返回 let indexPage = (html)=>{ return ` <!doctype html> <html lang="utf-8"> <head> <script> </script> </head> <body> <section id="hzpapp" >${html}</section> </body> <script src="/static/vendor.js"></script> <script src="/static/client.bundle.js"></script> </html> }
9. client.js中是否还能继续使用webpack的require.ensure ? 答:可以。但闪白明显,且node端返回html后会有报错,在加载脚本后该错误能忽略。
10. 若我使用的是mobx,该如何实例化store ? 答:每一个node请求,都应该返回一个新的独立的store实例,而不是每个node请求共用一个store实例(笔者易犯)。
本demo地址( 前端库React+mobx+ReactRouter ):github.com/Penggggg/react-ssr
위 내용은 React 서버 측 렌더링 예제에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!