開源不易,感謝你的支持,❤ star concent^_^css
nextjs
是一個很是流行的 React 服務端渲染應用框架,它很輕量,簡單易上手,社區活躍,因此當咱們使用react
寫一個須要ssr
(server side render)的應用的話,基本都會首選nextjs
,concent
是一個新生代的react
狀態管理方案,它內置依賴收集系統,同時兼具備0入侵、可預測、漸進式、高性能的特色,並提供了lifecyle
、composition api
等靈活的api且寫法超級簡單,讓你輕鬆駕馭超大規模的react應用。node
這裏咱們將使用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
這裏咱們將使用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的基礎示例目錄裏有個_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> ); }
大功告成,一個接入了concent
的next
應用就這樣產生了,是否是特別簡單呢?^_^
next
提供兩種級別的預渲染接口,即getServerSideProps
和getStaticProps
,兩種的區別是執行時機不一樣,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
歡迎小哥哥們來撩CloudBase CMS ,打造一站式雲端內容管理系統,它是雲開發推出的,基於 Node.js 的 Headless 內容管理平臺,提供了豐富的內容管理功能,安裝簡單,易於二次開發,並與雲開發的生態體系緊密結合,助力開發者提高開發效率。
concent
已爲其管理後臺提供強力支持,新版的管理界面更加美觀和體貼了。
也歡迎小哥哥們來撩FFCreator,它是一個基於node.js的輕量、靈活的短視頻加工庫。您只須要添加幾張圖片或視頻片斷再加一段背景音樂,就能夠快速生成一個很酷的視頻短片。
FFCreator
是一種輕量又簡單的解決方案,只須要不多的依賴和較低的機器配置就能夠快速開始工做。而且它模擬實現了animate.css90%的動畫效果,您能夠輕鬆地把 web 頁面端的動畫效果轉爲視頻,真的很給力。