react+redux教程(六)redux服務端渲染流程

來源:互聯網
上載者:User

標籤:

教程目錄

react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware

react+redux教程(二)redux的單一狀態樹完全替代了react的狀態機器?

react+redux教程(三)reduce()、filter()、map()、some()、every()、...展開屬性

react+redux教程(四)undo、devtools、router

react+redux教程(五)非同步、單一state樹結構、componentWillReceiveProps

react+redux教程(六)redux服務端渲染流程

連載中……

 

今天,我們要講解的是react+redux服務端渲染。個人認為,react擊敗angular的真正“殺手鐧”就是服務端渲染。我們為什麼要實現服務端渲染,主要是為了SEO。

例子

例子仍然是官方的計數器例子,不過我們實現了服務端渲染和state預先載入。

原始碼:

https://github.com/lewis617/myReact/tree/master/redux-examples/universal

虛擬API

首先,我們要類比一個api,用於非同步請求資料。代碼如下:

common/api/counter.js

function getRandomInt(min, max) {  return Math.floor(Math.random() * (max - min)) + min}export function fetchCounter(callback) {  // Rather than immediately returning, we delay our code with a timeout to simulate asynchronous behavior  setTimeout(() => {    callback(getRandomInt(1, 100))  }, 500)  // In the case of a real world API call, you‘ll normally run into a Promise like this:  // API.getUser().then(user => callback(user))}
服務端請求api,發送html串和state

server/server.js(部分代碼)

// This is fired every time the server side receives a requestapp.use(handleRender)function handleRender(req, res) {  // Query our mock API asynchronously  fetchCounter(apiResult => {    // Read the counter from the request, if provided    const params = qs.parse(req.query)    const counter = parseInt(params.counter, 10) || apiResult || 0    // Compile an initial state    const initialState = { counter }    // Create a new Redux store instance    const store = configureStore(initialState)    // Render the component to a string    const html = renderToString(      <Provider store={store}>        <App />      </Provider>    )    // Grab the initial state from our Redux store    const finalState = store.getState()    // Send the rendered page back to the client    res.send(renderFullPage(html, finalState))  })}function renderFullPage(html, initialState) {  return `    <!doctype html>    <html>      <head>        <title>Redux Universal Example</title>      </head>      <body>        <div id="app">${html}</div>        <script>          window.__INITIAL_STATE__ = ${JSON.stringify(initialState)}        </script>        <script src="/static/bundle.js"></script>      </body>    </html>    `}
  1. api寫好了,我們調用了這個api,即fetchCounter,這個api函數也會產生一個回調,我們在回調中擷取counter值
  2. 如果中介軟體請求中有參數,則const params = qs.parse(req.query),counter為parseInt(params.counter, 10)。否則counter為api的回調中返回的值apiResult,如果前兩個都沒有則為0。qs用於解析http請求中的querystring,就是?param=sth。
  3. 得到counter,我們就得到了state,用state作為參數,重建一個store執行個體,每次都要重建一個新的store執行個體。然後用react的服務端渲染產生一個html串,把它發送出去
  4. 同時,我們還要發送一個const finalState = store.getState()出去,讓用戶端拿到這個state渲染,為什嗎?因為要保證用戶端和服務端渲染的組件一樣。
“提了褲子不認人”的服務端渲染

既然有了服務端渲染,為何還要用用戶端渲染,因為服務端渲染是“提了褲子不認人”,渲染完,我們的程式就不會動了(因為是一堆字串),用戶端則可以讓程式繼續動起來,因為用戶端有js,可以調用方法重繪瀏覽器介面。

用戶端拿到state再渲染一次

既然要再渲染一次,為何還要服務端渲染?為了seo,我們的服務端渲染不只是給使用者看的,主要是給那些“低能”的網路爬蟲看的。

好吧,忍忍火,我們繼續工作,用戶端再渲染一次。

const initialState = window.__INITIAL_STATE__const store = configureStore(initialState)const rootElement = document.getElementById(‘app‘)render(  <Provider store={store}>    <App/>  </Provider>,  rootElement)

其實用戶端渲染也就拿到個初始state,然後render而已,沒有很多代碼。

我們的state是從window.__INITIAL_STATE__擷取的,因為服務端把要給用戶端的state放在了這個全域變數上面。

"玄乎"的預載state

預載state,說得這麼“玄乎”,好像很高大上,其實就是把state在伺服器那邊就產生好,然後傳過來直接給用戶端用。沒有那麼“玄乎”。

 

react+redux教程(六)redux服務端渲染流程

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.