>웹 프론트엔드 >JS 튜토리얼 >React 서버 측 렌더링 예제에 대한 자세한 설명

React 서버 측 렌더링 예제에 대한 자세한 설명

零下一度
零下一度원래의
2017-07-02 10:12:581865검색

최대한 빠른 렌더링 시간과 빠른 페이지 응답 속도가 필요할 때 서버사이드 렌더링을 사용하겠습니다. 이 글에서는 주로 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>
)

로 React-router를 통한 라우팅

구성 파일

routes.js가 있습니다. 2. 코드는 앞면과 뒷면으로 구성되어 있습니다. 각 플랫폼에서 공유한다면, 플랫폼마다 다른 코드를 어떻게 운용할 수 있나요? 답변: 웹팩을 통해.


 // webpack.client.config.js
plugins: [
   new webpack.DefinePlugin({
     &#39;isServer&#39;: false,
     &#39;isClient&#39;: true
   })
 ]
// webpack.server.config.js
plugins: [
   new webpack.DefinePlugin({
     &#39;isServer&#39;: true,
     &#39;isClient&#39;: 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(&#39;/todo&#39;, (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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.