助力ssr,使用concent爲nextjs應用加點料

開源不易,感謝你的支持,❤ star concent^_^
css

序言

nextjs是一個很是流行的 React 服務端渲染應用框架,它很輕量,簡單易上手,社區活躍,因此當咱們使用react寫一個須要ssr(server side render)的應用的話,基本都會首選nextjsconcent是一個新生代的react狀態管理方案,它內置依賴收集系統,同時兼具備0入侵、可預測、漸進式、高性能的特色,並提供了lifecylecomposition api等靈活的api且寫法超級簡單,讓你輕鬆駕馭超大規模的react應用。node

Hello next

這裏咱們將使用create-next-app命令來安裝一個基礎的next示例應用react

npx create-next-app hello-next

執行完畢後,能夠看到一個以下的目錄結構git

|____public
|____pages
| |____ _app.js   // next應用默認的根組件
| |____index.js   // 默認首頁
| |____api        // api路由文件
| | |____hello.js

以後咱們在項目根目錄執行npm run dev將看到一個由next驅動的ssr默認首頁
github

Hello concent

這裏咱們將使用create-react-app命令來安裝一個基礎的concent示例應用web

npx create-react-app hello-concent --template concent-ts

執行完畢後,能夠看到一個以下的目錄結構npm

|____index.tsx
|____App.tsx
|____types            // store的類型定義處
|____features           // 功能組件列表
| |____counter          // counter功能
| | |____Counter.tsx        // counter組件
| | |____model            // counter模型(包含state,reducer,computed)
|____models            // 其它全局通用的模型定義
|____configs

進入項目目錄執行npm i,而後執行npm start便可看到一個默認的計數器頁面
json

你也能夠點擊 這裏在線瞭解和編輯它。

固然了在已有的項目裏集成concent裏也超級簡單,由於它無需頂層提供Provider,只須要提早配置好模型便可。api

import { run } from 'concent';

run({ // 定義一個counter模型
  counter: {
    state: { num: 1, bigNum: 10 },
    reducer: {
      add(payload, moduleState) {
        return { num: moduleState + 1 };
      },
      async asyncAddBig() {
        await new Promise(resolve => setTimeout(resolve, 1000));
        return { bigNum: moduleState + 10 };
      }
    },
    computed: {
      doubleNum: ({ num }) => num * 2, // 僅當num發生變化才觸發此函數
    }
  }
})

以後就能夠全局即插即用啦,類組件和函數組件均可以用一樣的方式去讀取數據或調用方法,敲重點啦,若是ui處是有條件語句控制是否要消費狀態或衍生數據的話,推薦延遲解構的寫法,這樣可讓concent在每一輪渲染完畢後收集到視圖對數據的最小粒度依賴數組

// ###### 函數組件
function Demo(){
  // 如 state 和 moduleComputed 是按需讀取的,推薦延遲解構的寫法
  const { state: { num, numBig }, moduleComputed: { doubleNum }, mr } = useConcent('counter'); 
  // ... ui 邏輯,綁數據、綁方法
}

// ###### 類組件
const DemoCls = register('counter')(
  class DemoCls extends React.Component{
   render(){
      const { state: { num, numBig }, moduleComputed: { doubleNum }, mr } = this.ctx; 
      // ... ui 邏輯,綁數據、綁方法
    }
  }
)

在next裏引入concent

next的基礎示例目錄裏有個_app.js文件,它是next應用的根組件

import '../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

因使用concent以前必需提早配置好模型,因此咱們只需提早建立一個runConcent.js文件

import { run } from 'concent'
import * as models from './models';

run(models);

而後在_app.js文件引入便可,這樣根組件下的全部子組件都可以正確獲取到store的數據和調動store的方法了。

import '../styles/globals.css'
+ import './runConcent'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

接着咱們在next的pages目錄下建立一個counter.js文件,表明這是一個頁面組件,這樣瀏覽器端能夠用/counter路由來訪問到這個組件的渲染視圖了。

import React from 'react'
import { useConcent } from 'concent'
import router from 'next/router'

// use next/router to do browser side router jump
function toHomePage(){
  router.push('/');
}

export default function Counter() {
  const { state, mr, moduleComputed } = useConcent('home')

  return (
    <div>
      this is counter page
      <h1>num: {state.num}</h1>
      <h1>doubleNum: {moduleComputed.doubleNum}</h1>
      <button onClick={mr.add}>add</button>
      <button onClick={toHomePage}>to home page</button>
    </div>
  );
}

大功告成,一個接入了concentnext應用就這樣產生了,是否是特別簡單呢?^_^

支持預渲染

next提供兩種級別的預渲染接口,即getServerSidePropsgetStaticProps,兩種的區別是執行時機不一樣,getServerSideProps是每次請求頁面都會執行,而getStaticProps是構建時執行,咱們先處理getServerSideProps這種狀況吧,看看如何集合concent作預渲染支持。

首先咱們不考慮concent的存在,在next裏作預渲染支持,只須要在你的頁面組件裏暴露一個getServerSideProps接口便可。

// 此函數在每次請求改頁面時被調用
export async function getServerSideProps() {
  // 調用外部 API 獲取博文列表
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // 經過返回 { props: posts } 對象,PostPage 組件在渲染時將接收到 `posts` 參數
  return {
    props: { posts },
  }
}

function PostPage({ posts }) { // 這裏接收到了 posts 參數
  // Render posts...
}

export default PostPage

之因此Blog可以接到posts,除了暴露這個getServerSideProps這個接口以外,咱們再觀察一下_app.js這個根組件文件內容,能夠發現關鍵點所在!

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}
export default MyApp

參數列表裏的pageProps便是getServerSideProps返回結果裏props指向的對象,而後next將其透傳到目標頁面組件上,因此咱們纔可以在PostPage參數列表裏解構出posts

因此咱們的切入點就能夠從這裏入手了,咱們把getStaticProps的返回結果作一下格式約束,形如{module:string, state: object}這樣的結構,而後在_app.js文件裏記錄到store便可

// 此函數在每次請求時被調用
export async function getServerSideProps() {
  // 調用外部 API 獲取博文列表
  await delay();
  const posts = [
    { id: 1, name: 'post1 -----' },
    { id: 2, name: 'post2 --- welcome to use concent' },
  ];
  // 這個返回對象會透傳給根組件的pageProps,在此返回狀態所屬的模塊和狀態實體對象
  // 在那裏將狀態記錄到store
  return {
    props: {
      module: 'test',
      state: { posts },
    }
  };
}

此時的根組件文件改變以下

import '../styles/globals.css';
+ import './runConcent';
+ import { setState } from 'concent';

function MyApp({ Component, pageProps }) {
  // 這裏記錄 getServerSideProps 的返回狀態到store的對應模塊
+  if (pageProps.module) {
+    setState(pageProps.module, pageProps.state);
+  }
  return <Component {...pageProps} />
}
export default MyApp;

而後咱們實現的頁面組件post-page代碼以下

const PostList = React.memo(function () {
  const { state } = useConcent('test');
  return (
    <div>
      {state.posts.map(item => <h3 key={item.id}>{item.name}</h3>)}
    </div>
  );
});

const PostLength = React.memo(function () {
  const { state } = useConcent('test');
  return <h1>{state.posts.length}</h1>;
});

export default function PostPage() {
  return (
    <div>
      <h1>this is post page</h1>
      <PostList />
      <PostLength />
      <button onClick={toHomePage}>to home page</button>
    </div>
  );
}

接着咱們打開瀏覽器訪問/post-page頁面吧,點擊查看源碼將會看到這是一個服務器端預渲染的頁面

同理,咱們也可將getServerSideProps替換爲getStaticProps,上面的整個流程將依然正常工做,歡迎各位看官clone示例代碼來親自體驗一下。

git clone https://github.com/concentjs/ssr-demo-1

附錄

doc

CloudBase CMS

歡迎小哥哥們來撩CloudBase CMS ,打造一站式雲端內容管理系統,它是雲開發推出的,基於 Node.js 的 Headless 內容管理平臺,提供了豐富的內容管理功能,安裝簡單,易於二次開發,並與雲開發的生態體系緊密結合,助力開發者提高開發效率。

concent已爲其管理後臺提供強力支持,新版的管理界面更加美觀和體貼了。

FFCreator

也歡迎小哥哥們來撩FFCreator,它是一個基於node.js的輕量、靈活的短視頻加工庫。您只須要添加幾張圖片或視頻片斷再加一段背景音樂,就能夠快速生成一個很酷的視頻短片。

FFCreator是一種輕量又簡單的解決方案,只須要不多的依賴和較低的機器配置就能夠快速開始工做。而且它模擬實現了animate.css90%的動畫效果,您能夠輕鬆地把 web 頁面端的動畫效果轉爲視頻,真的很給力。
相關文章
相關標籤/搜索