整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          2024 年,你應該知道的 5 種 React 設計

          2024 年,你應該知道的 5 種 React 設計模式

          者 | Lakindu Hewawasam

          譯者 | 許學文

          策劃 | 丁曉昀

          如果你在開發工作中使用的是 React 框架,那么首當其沖要學習的就是思考如何設計組件。組件設計并非簡單地將多個組件合成一個集合,而是需要思考如何設計更小、復用性更強的組件。例如,思考下面這張組件圖:



          簡化的組件圖


          圖中有三個組件,分別是:


          1. Typography 組件
          2. Footer 組件
          3. Sizeable Box 組件


          如圖所示,Typography 組件同時被 Footer 和 Sizeable Box 組件使用。通常我們以為這樣,就能構建一個簡單、易維護和易排除錯誤的應用了。但其實只是這樣思考組件的設計是遠遠不夠的。


          如果你知道如何從組件的視角思考問題,就可以通過在 React 組件中使用設計模式來提高代碼的整體模塊性、可擴展性和可維護性。


          因此,下面這五種設計模式,是你在使用 React 時必須要掌握的。


          模式一:基礎組件


          首先,在使用 React 時候,請嘗試為應用設計基礎組件。


          基礎UI組件,就是一個具備默認行為且支持定制化的組件。


          例如,每個應用都會通過基礎的樣式、按鈕設計或者基礎的排版,來實現應用在視覺和交互上的一致性。這些組件的設計特點是:


          1. 組件會應用一組默認的配置。因此,使用者無需進行任何額外的配置,就可以快速基于默認配置使用組件。
          2. 組件可以支持定制化,使用者通過定制化可以覆蓋組件的默認行為,從而為組件提供自定義的整體視覺和交互效果。


          通過一個 Button 組件就能很好地說明基礎組件模式的實現。示例如下:


          1. Button 組件可能會有諸如空心、實心等不同形態。
          2. Button 組件可能會有默認的文本。


          現在你就可以利用基礎組件模式進行設計,使組件的使用者可以改變其行為。請參考我基于基礎組件模式完成的Button組件,示例代碼如下:


          import React, { ButtonHTMLAttributes } from 'react';
          
          
          
          
          // 按鈕組件的形態:實心或者空心
          type ButtonVariant='filled' | 'outlined';
          
          
          
          
          export type ButtonProps={
            /**
             * the variant of the button to use 
             * @default 'outlined'
             */
            variant?: ButtonVariant;
          } & ButtonHTMLAttributes<HTMLButtonElement>;;
          
          
          
          
          const ButtonStyles: { [key in ButtonVariant]: React.CSSProperties }={
            filled: {
              backgroundColor: 'blue', // Change this to your filled button color
              color: 'white',
            },
            outlined: {
              border: '2px solid blue', // Change this to your outlined button color
              backgroundColor: 'transparent',
              color: 'blue',
            },
          };
          
          
          
          
          export function Button({ variant='outlined', children, style, ...rest }: ButtonProps) {
            return (
              <button
                type='button'
                style={{
                  ...ButtonStyles[variant],
                  padding: '10px 20px',
                  borderRadius: '5px',
                  cursor: 'pointer',
                  ...style
                }} {...rest}>
                {children}
              </button>
            );
          }

          復制代碼


          仔細觀察代碼會發現,這里 Button 組件的 props 類型合并了原生 HTML 中 button 標簽屬性的全部類型。這意味著,使用者除了可以為 Button 組件設置默認配置外,還可以設置諸如 onClick、aria-label 等自定義配置。這些自定義配置會通過擴展運算符傳遞給 Button 組件內部的 button 標簽。


          通過不同的上下文設置,可以看到不同的 Button 組件的形態,效果截圖如下圖。


          這個可以查看具體設置:

          https://bit.cloud/lakinduhewa/react-design-patterns/base/button/~compositions



          基礎組件在不同上下文中的使用效果


          通過不同的上下文,你可以設定組件的行為。這可以讓組件成為更大組件的基礎。


          模式二:組合組件


          在成功創建了基礎組件后,你可能會希望基于基礎組件創建一些新的組件。


          例如,你可以使用之前創建的 Button 組件來實現一個標準的 DeleteButton 組件。通過在應用中使用該 DeleteButton,可以讓應用中所有刪除操作在顏色、形態以及字體上保持一致。


          不過,如果出現重復組合一組組件來實現相同效果的現象,那么你可以考慮將它們封裝到一個組件中。


          下面,讓我們來看看其中一種實現方案:

          https://bit.cloud/lakinduhewa/react-design-patterns/composition/delete-button



          使用組合模式創建組件


          如上面的組件依賴圖所示,DeleteButton 組件使用基礎的 Button 組件為所有與刪除相關的操作提供標準的實現。下面是基本代碼實現:


          // 這里引入了,基礎按鈕組件和其props
          import { Button, ButtonProps } from '@lakinduhewa/react-design-patterns.base.button';
          import React from 'react';
          
          
          
          
          export type DeleteButtonProps={} & ButtonProps;
          
          
          
          
          export function DeleteButton({ ...rest }: DeleteButtonProps) {
            return (
              <Button
                variant='filled'
                style={{
                  background: 'red',
                  color: 'white'
                }}
                {...rest}
              >
                DELETE
              </Button>
            );
          }

          復制代碼


          我們使用基于模式一創建的 Button 組件來實現的 DeleteButton 組件的效果如下:



          現在我們可以在應用中使用統一的刪除按鈕。此外,如果你使用類似 Bit 的構建系統進行組件的設計和構建,那么當 Button 組件發生改變時,可以讓CI服務自動將此改變傳遞到DeleteButton組件上,就像下面這樣(當 Button 組件從 0.0.3 升級到了 0.0.4,那么 CI 服務會自動觸發,將 DeleteButton 組件從 0.0.1 升級到 0.0.2):


          Bit 上的一個 CI 構建


          模式三:使用 Hooks


          React Hooks 是React v16就推出來的特性,它不依賴類組件實現狀態管理、負效應等概念。簡而言之,就是你可以通過利用 Hooks API 擺脫對類組件的使用需求。useSate 和 useEffect 是最廣為人知的兩個 Hooks API,但本文不打算討論它們,我想重點討論如何利用 Hooks 來提高組件的整體可維護性。


          例如,請考慮下面這個場景:


          1. 有一個 BlogList 組件。
          2. BlogList 組件會通過調用一個簡單的 API,獲取博客文章列表數據,同時將其渲染在組件上。


          基于上面的案例,你可能會像下面這樣將 API 邏輯直接寫在函數組件中:


          import React, { useState, useEffect } from 'react';
          import axios from 'axios';
          const BlogList=()=> {
              const [blogs, setBlogs]=useState([]);
              const [isLoading, setIsLoading]=useState(true);
              const [error, setError]=useState(null);
              useEffect(()=> {
                  axios.get('https://api.example.com/blogs')
                      .then(response=> {
                          setBlogs(response.data);
                          setIsLoading(false);
                      })
                      .catch(error=> {
                          setError(error);
                          setIsLoading(false);
                      });
              }, []);
              if (isLoading) return <div>Loading...</div>;
              if (error) return <div>Error: {error.message}</div>;
              return (
                  <div>
                      <h2>Blog List</h2>
                      <ul>
                          {blogs.map(blog=> (
                              <li key={blog.id}>{blog.title}</li>
                          ))}
                      </ul>
                  </div>
              );
          };
          export default BlogList;

          復制代碼


          這樣寫,組件也能正常工作。它將會獲取博客文章列表并且渲染在 UI 上。但是,這里將 UI 邏輯和 API 邏輯混在一起了。


          理想情況下,React 組件應該不需要關系如何獲取數據。而只需要關心接收一個數據數組,然后將其呈現在 DOM 上。


          因此,實現這一目標的最佳方法是將 API 邏輯抽象到 React Hook 中,以便在組件內部進行調用。這樣做就可以打破 API 調用與組件之間的耦合。通過這種方式,就可以在不影響組件的情況下,修改底層的數據獲取邏輯。


          其中一種實現方式如下。


          1.useBlog hook


          import { useEffect, useState } from 'react';
          import { Blog } from './blog.type';
          import { Blogs } from './blog.mock';
          
          
          
          
          export function useBlog() {
            const [blogs, setBlogs]=useState<Blog[]>([]);
            const [loading, setLoading]=useState<boolean>(false);
          
          
          
          
            useEffect(()=> {
              setLoading(true);
               // 注意:這里的setTimeout非實際需要,只是為了模擬API調用
              setTimeout(()=> {
                setBlogs(Blogs);
                setLoading(false);
              }, 3000);
            }, []);
          
          
          
          
            return { blogs, loading }
          }

          復制代碼


          如上代碼所示,useBlog hook 獲取博客列表數據,然后賦值給狀態變量,最后通過導出變量給到消費者(BlogList 組件)使用:



          Hook 效果


          2.BlogList 組件


          import React from 'react';
          // 引入上面封裝的 useBlog hook
          import { useBlog } from '@lakinduhewa/react-design-patterns.hooks.use-blog';
          export function BlogList() {
            const { blogs, loading }=useBlog();
            if (loading) {
              return (
                <p>We are loading the blogs...</p>
              )
            }
            return (
              <ul>
                {blogs.map((blog)=> <ol
                  key={blog.id}
                >
                  {blog.title}
                </ol>)}
              </ul>
            );
          }

          復制代碼



          BlogList 組件效果


          通過調用 useBlog 和使用其導出的狀態變量,我們在 BlogList 組件中使用了 Hooks。如此,相對于之前,我們可以減少大量代碼,并以最少的代碼和精力維護兩個組件。


          此外,當你使用類似 Bit 這樣的構建系統時(就像我一樣),只需將 useBlog 組件導入本地開發環境,然后再修改完成之后重新推送回 Bit Cloud。Bit Cloud 的構建服務器可以依托依賴樹將此修改傳遞給整個應用。因此如果只執行一些簡單修改,甚至不需要訪問整個應用。


          模式四:React Providers


          此模式的核心是解決組件狀態共享。我們都曾是 props 下鉆式傳遞的受害者。但如果你還沒有經歷過,那這里簡單解釋下:“props 下鉆式傳遞”就是當你在組件樹中進行 props 傳遞時,這些 props 只會在最底層組件中被使用,而中間層的組件都不會使用該 props。例如,看看下面這張圖:

          props 下鉆式傳遞


          從 BlogListComponent 一直向下傳遞一個 isLoading 的 props 到 Loader。但是,isLoading 只在 Loader 組件中使用。因此,在這種情況下,組件不但會引入不必要的 props,還會有性能開銷。因為當 isLoading 發生變化時,即使組件沒有使用它,React 依然會重新渲染你的組件樹。


          因此,解決方案之一就是通過利用 React Context 來使用 React Context Provider 模式。React Context 是一組組件的狀態管理器,通過它,你可以為一組組件創建特定的上下文。通過這種方式,你可以在上下文中定義和管理狀態,讓不同層級的組件都可以直接訪問上下文,并按需使用 props。這樣就可以避免 props 下鉆式傳遞了。


          主題組件就是該模式的一個常見場景。例如,你需要在應用程序中全局訪問主題。但將主題傳遞到應用中的每個組件并不現實。你可以創建一個包含主題信息的 Context,然后通過 Context 來設置主題。看一下我是如何通過React Context實現主題的,以便更好地理解這一點:

          https://bit.cloud/lakinduhewa/react-design-patterns/contexts/consumer-component


          import { useContext, createContext } from 'react';
          export type SampleContextContextType={
            /**
             * primary color of theme.
             */
            color?: string;
          };
          export const SampleContextContext=createContext<SampleContextContextType>({
            color: 'aqua'
          });
          export const useSampleContext=()=> useContext(SampleContextContext);

          復制代碼


          在 Context 中定義了一種主題顏色,它將在所有實現中使用該顏色來設置字體顏色。接下來,我還導出了一個 hook——useSampleContext,該 hook 讓消費者可以直接使用 Context。


          只是這樣還不行,我們還需要定義一個 Provider。Provider 是回答 "我應該與哪些組件共享狀態?"問題的組件。Provider的實現示例如下:


          import React, { ReactNode } from 'react';
          import { SampleContextContext } from './sample-context-context';
          export type SampleContextProviderProps={
            /**
             * primary color of theme.
             */
            color?: string,
            /**
             * children to be rendered within this theme.
             */
            children: ReactNode
          };
          export function SampleContextProvider({ color, children }: SampleContextProviderProps) {
            return <SampleContextContext.Provider value={{ color }}>{children}</SampleContextContext.Provider>
          }

          復制代碼


          Provider 在管理初始狀態和設置 Context 可訪問狀態的組件方面起著至關重要的作用。


          接下來,你可以創建一個消費者組件來使用狀態:



          消費者組件


          模式五:條件渲染


          最后一個想和大家分享的是條件渲染模式。今天,人人都知道 React 中的條件渲染。它通過條件判斷來選擇組件進行渲染。


          但在實際使用中我們的用法常常是錯誤的:


          // ComponentA.js
          const ComponentA=()=> {
              return <div>This is Component A</div>;
          };
          // ComponentB.js
          const ComponentB=()=> {
              return <div>This is Component B</div>;
          };
          // ConditionalComponent.js
          import React, { useState } from 'react';
          import ComponentA from './ComponentA';
          import ComponentB from './ComponentB';
          const ConditionalComponent=()=> {
              const [toggle, setToggle]=useState(true);
              return (
                  <div>
                      <button onClick={()=> setToggle(!toggle)}>Toggle Component</button>
                      {toggle ? <ComponentA /> : <ComponentB />}
                  </div>
              );
          };
          export default ConditionalComponent;

          復制代碼


          你是否注意到,這里我們將基于條件的邏輯耦合到了 JSX 代碼片段中。通常,你不應該在 JSX 代碼中中添加任何與計算相關的邏輯,而只將與 UI 渲染相關的內容放在其中。


          解決這個問題的方法之一是使用條件渲染組件模式。創建一個可重用的 React 組件,該組件可以根據條件渲染兩個不同的組件。它的實現過程如下:


          import React, { ReactNode } from 'react';
          export type ConditionalProps={
            /**
             * the condition to test against
             */
            condition: boolean
            /**
             * the component to render when condition is true
             */
            whenTrue: ReactNode
            /**
             * the component to render when condition is false
             */
            whenFalse: ReactNode
          };
          export function Conditional({ condition, whenFalse, whenTrue }: ConditionalProps) {
            return condition ? whenTrue : whenFalse;
          }

          復制代碼


          我們創建了一個可以按條件渲染兩個組件的組件。當我們將其集成到其他組件中時,會使代碼更簡潔,因為無需在 React 組件中加入復雜的渲染邏輯。你可以像下面這樣使用它:


          export const ConditionalTrue=()=> {
            return (
              <Conditional
                condition
                whenFalse="You're False"
                whenTrue="You're True"
              />
            );
          }
          export const ConditionalFalse=()=> {
            return (
              <Conditional
                condition={false}
                whenFalse="You're False"
                whenTrue="You're True"
              />
            );
          }

          復制代碼


          實際的輸入如下:



          總結


          掌握這五種設計模式,為 2024 年做好充分準備,構建出可擴展和可維護的應用吧。


          如果你想詳細深入本文中討論的模式,請隨時查看我在Bit Cloud的空間:

          https://bit.cloud/lakinduhewa/react-design-patterns


          感謝你的閱讀!

          原文鏈接:2024年,你應該知道的5種React設計模式_架構/框架_InfoQ精選文章

          日常開發中,我們有一些組件的樣式是重復的。

          例如,Text 組件的 width、height 都是一樣的。

          @Entry
          @Component
          struct Index {
            build() {
              Column() {
                Text("春明不覺曉")
                  .width(100)
                  .height(50)
          
                Text("處處聞啼鳥")
                  .width(100)
                  .height(50)
          
                Text("夜來風雨聲")
                  .width(100)
                  .height(50)
          
                Text("花落知多少")
                  .width(100)
                  .height(50)
              }
              .width('100%')
            }
          }

          那么,我們可以將這些重復的樣式抽出來,做成一個公共樣式

          公共樣式是一個函數,格式為:@Style 樣式名稱() { 樣式描述 }

          例如這里的 @Style textSize(){}。

          @Entry
          @Component
          struct Index {
            @Styles textSize(){
              .width(100)
              .height(50)
            }
          
            build() {
              Column() {
                Text("春明不覺曉")
                  .width(100)
                  .height(50)
          
                Text("處處聞啼鳥")
                  .width(100)
                  .height(50)
          
                Text("夜來風雨聲")
                  .width(100)
                  .height(50)
          
                Text("花落知多少")
                  .width(100)
                  .height(50)
              }
              .width('100%')
            }
          }

          接下來,我們就可以使用 textSize 去替換掉那些重復的樣式。

          @Entry
          @Component
          struct Index {
            @Styles textSize(){
              .width(100)
              .height(50)
            }
          
            build() {
              Column() {
                Text("春明不覺曉")
                  .textSize()
          
                Text("處處聞啼鳥")
                  .textSize()
          
                Text("夜來風雨聲")
                  .textSize()
          
                Text("花落知多少")
                  .textSize()
              }
              .width('100%')
            }
          }

          運行結果是不變的:

          使用公共樣式可以幫我們減少很多重復的代碼。

          推薦大家在日常開發中多多使用 @Style 定義公共樣式。

          注意:當前 @Styles 僅支持通用屬性和通用事件

          通用屬性文檔地址:

          https://developer.harmonyos.com/cn/docs/documentation/doc-references-V3/ts-universal-attributes-size-0000001428061700-V3

          通用事件文檔地址:

          https://developer.harmonyos.com/cn/docs/documentation/doc-references-V3/ts-universal-events-click-0000001477981153-V3

          還有一點需要注意的是,@Styles方法不支持參數。下列操作是不允許的:

          // 錯誤寫法,不允許有參數
          @Styles textSize(message: string){
            .width(100)
            .height(50)
          }

          至此,@Style 基本使用方法介紹完畢。

          者|Next.js 團隊

          譯者|無明

          出處丨前端之巔

          在經過 26 次金絲雀發布和 340 萬次下載之后,近日,我們正式發布了 Next.js 7.0,新功能包括:

          • DX 改進:啟動速度提高 57%,重新編譯速度提高 42%;
          • 使用 react-error-overlay 更好地報告錯誤;
          • 編譯管道升級:Webpack 4 和 Babel 7;
          • 標準化的動態導入;
          • 靜態 CDN 支持;
          • 較小的初始 HTML 載荷;
          • App 和 Page 之間的 React Context(服務器端渲染)。

          DX 改進

          Next.js 的主要目標之一是提供最佳的性能和開發者體驗。最新版本為構建和調試管道帶來了很多重大改進。

          得益于 Webpack 4 和 Babel 7,以及我們對代碼庫做出的很多改進和優化,Next.js 現在在開發過程中的啟動速度提高了 57%。

          我們新增了增量編譯緩存,讓變更代碼的構建速度快了 40%。

          以下是我們收集的一些示例數據:


          因為使用了 webpackbar,在開發和構建的同時可以看到更好的實時反饋:


          使用 react-error-overlay 更好地報告錯誤

          準確地渲染錯誤對于良好的開發和調試體驗來說是至關重要的。到目前為止,我們可以渲染錯誤消息和堆棧跟蹤信息。我們在此基礎上更進一步,我們使用 react-error-overlay 來豐富堆棧跟蹤信息:

          • 準確的服務器端和客戶端錯誤位置;
          • 高亮顯示錯誤來源;
          • 完整的堆棧跟蹤信息。

          這是之前和之后的錯誤顯示比較:


          另外,借助 react-error-overlay,你只需單擊特定代碼塊就可以輕松打開文本編輯器。

          支持 Webpack 4

          從發布第一個版本以來,Next.js 一直使用 Webpack 來打包代碼和重用豐富的插件。Next.js 現在使用了最新的 Webpack 4,其中包含很多改進和 bug 修復。

          • 支持.mjs 源文件;
          • 代碼拆分改進;
          • 更好的搖樹優化(刪除未使用的代碼)支持。

          另一個新功能是支持 WebAssembly,Next.js 甚至可以進行 WebAssembly 服務器渲染。

          這里有一個例子:

          https://github.com/zeit/next.js/tree/canary/examples/with-webassembly

          CSS 導入

          因為使用了 Webpack 4,我們引入了一種從捆綁包中提取 CSS 的新方法,這個插件叫作 mini-extract-css-plugin(https://github.com/webpack-contrib/mini-css-extract-plugin)。

          mini-extract-css-plugin 提供了 @zeit/next-css、@zeit/next-less、@zeit/next-sass 和 @zeit/next-stylus。

          這些 Next.js 插件的新版本解決了與 CSS 導入相關的 20 個問題,例如,現在支持 import() 動態導入 CSS:

          // components/my-dynamic-component.js
          import './my-dynamic-component.css'
          export default ()=> <h1>My dynamic component</h1>
          // pages/index.js
          import dynamic from 'next/dynamic'
          const MyDynamicComponent=dynamic(import('../components/my-dynamic-component'))
          export default ()=> <div>
           <MyDynamicComponent/>
          </div>
          

          一個重大改進是現在不再需要在 pages/_document.js 中添加一下內容:

          <link rel="stylesheet" href="/_next/static/style.css" />
          

          Next.js 會自動注入這個 CSS 文件。在生產環境中,Next.js 還會自動向 CSS URL 中添加內容哈希,當文件發生變更時,最終用戶就不會得到舊文件,并且能夠獲得不可變的永久緩存。

          簡而言之,要在 Next.js 項目中支持導入.css 文件,只需要在 next.config.js 中注冊 withCSS 插件:

          const withCSS=require('@zeit/next-css')
          module.exports=withCSS({/* my next config */})
          

          標準化動態導入

          從版本 3 開始,Next.js 就通過 next/dynamic 來支持動態導入。

          作為這項技術的早期采用者,我們必須自己編寫解決方案來處理 import()。

          因此,Next.js 逐漸缺失 Webpack 后來引入的一些功能,包括 import()。

          例如,無法手動命名和捆綁某些文件:

          import(/* webpackChunkName: 'my-chunk' */ '../lib/my-library')
          

          另一個例子是在 next/dyanmic 模塊之外使用 import()。

          從 Next.js 7 開始,我們不再直接使用默認的 import(),Next.js 為我們提供了開箱即用的 import() 支持。

          這個變更也是完全向后兼容的。使用動態組件非常簡單:

          import dynamic from 'next/dynamic'
          const MyComponent=dynamic(import('../components/my-component'))
          export default ()=> {
           return <div>
           <MyComponent />
           </div>
          }
          

          這段代碼的作用是為 my-component 創建一個新的 JavaScript 文件,并只在渲染< MyComponent/>時加載它。

          最重要的是,如果沒有進行渲染,< script>標記就不會出現在初始 HTML 文檔中。

          為了進一步簡化我們的代碼庫并利用優秀的 React 生態系統,在 Next.js 7 中,我們使用 react-loadable 重寫了 next/dynamic 模塊。這為動態組件引入了兩個很棒的新特性:

          • 使用 next/dynamic 的 timeout 選項設置超時;
          • 使用 next/dynamic 的 delay 選項設置組件加載延遲。例如,如果導入非常快,可以通過這個選項讓加載組件在渲染加載狀態之前等待一小段時間。

          支持 Babel 7

          Next.js 6 中就已經引入了 Babel 7 測試版。后來 Babel 7 穩定版本發布,現在,Next.js 7 正在使用這個新發布的穩定版 Babel 7。

          一些主要特性:

          • Typescript 支持,在 Next.js 中可以使用 @zeit/next-
          • typescript;
          • 片段語法<>支持;
          • babel.config.js 支持;
          • 通過 overrides 屬性將預設 / 插件應用于文件或目錄的子集。

          如果你的 Next.js 項目中沒有自定義 Babel 配置,那么就不存在重大變更。

          但如果你具有自定義 Babel 配置,則必須將相應的自定義插件 / 預設升級到最新版本。

          如果你從 Next.js 6 以下的版本升級,可以使用 babel-upgrade 工具。

          除了升級到 Babel 7 之外,當 NODE_ENV 被設置為 test 時,Next.js Babel 預設(next/babel)現在默認將 modules 選項設置為 commonjs。

          這個配置選項通常是在 Next.js 項目中創建自定義.babelrc 的唯一理由:

          {
           "env": {
           "development": {
           "presets": ["next/babel"]
           },
           "production": {
           "presets": ["next/babel"]
           },
           "test": {
           "presets": [["next/babel", { "preset-env": { "modules": "commonjs" } }]]
           }
           }
          }
          

          使用 Next.js 7,這將變成:

          {
           "presets": ["next/babel"]
          }
          

          現在可以刪除.babelrc,因為在沒有 Babel 配置時,Next.js 將自動使用 next/babel。

          較小的初始 HTML 載荷

          Next.js 在預渲染 HTML 時會將頁面內容放在< html>、< head>、< body>結構中,并包含頁面所需的 JavaScript 文件。

          這個初始載荷之前約為 1.62kB。在 Next.js 7 中,我們優化了初始 HTML 載荷,現在為 1.5kB,減少了 7.4%,讓頁面變得更加精簡。


          我們主要通過以下幾種方式來縮小文件:

          • 移除 __next-error div;
          • 內聯腳本被最小化,在未來的版本中,它們將被完全移除;
          • 去掉未使用的 NEXT_DATA 屬性,例如 nextExport 和 assetPrefix 屬性。

          靜態 CDN 支持

          在 Next.js 5 中,我們引入了 assetPrefix 支持,讓 Next.js 可以自動從某個位置(通常是 CDN)加載資源。如果你的 CDN 支持代理,可以使用這種辦法。你可以像這樣請求資源:

          https://cdn.example.com/_next/static/<buildid>/pages/index.js
          

          通常,CDN 先檢查緩存中是否包含這個文件,否則直接從源中請求文件。

          不過,某些解決方案需要將目錄直接預先上傳到 CDN 中。這樣做的問題在于 Next.js 的 URL 結構與.next 文件夾中的文件夾結構不匹配。例如我們之前的例子:

          https://cdn.example.com/_next/static/<buildid>/pages/index.js
          // 映射到:
          .next/page/index.js
          

          在 Next.js 7 中,我們改變了.next 的目錄結構,讓它與 URL 結構相匹配:

          https://cdn.example.com/_next/static/<buildid>/pages/index.js
          // 映射到:
          .next/static/<buildid>/pages/index.js
          

          盡管我們建議使用代理類型的 CDN,但新結構也允許不同類型 CDN 的用戶將.next 目錄上傳到 CDN。

          styled-jsx 3

          我們也引入了 styled-jsx 3,Next.js 的默認 CSS-in-JS 解決方案,現在已經為 React Suspense 做好了準備。

          如果一個組件不屬于當前組件作用域的一部分,那么該如何設置這個子組件的樣式呢?例如,如果你將一個組件包含在父組件中,并只有當它被用在父組件中時才需要特定的樣式:

          const ChildComponent=()=> <div>
           <p>some text</p>
          </div>
          export default ()=> <div>
           <ChildComponent />
           <style jsx>{`
           p { color: black }
           `}</style>
          </div>
          

          上面的代碼試圖選擇 p 標簽,但其實不起作用,因為 styled-jsx 樣式被限定在當前組件,并沒有泄漏到子組件中。解決這個問題的一種方法是使用:global 方法,將 p 標記的前綴移除。但這樣又引入了一個新問題,即樣式泄露到了整個頁面中。

          在 styled-jsx 3 中,通過引入一個新的 API css.resolve 解決了這個問題,它將為給定的 syled-jsx 字符串生成 className 和< style>標簽(styles 屬性):

          import css from 'styled-jsx/css'
          const ChildComponent=({className})=> <div>
           <p className={className}>some text</p>
          </div>
          const { className, styles }=css.resolve`p { color: black }`
          export default ()=> <div>
           <ChildComponent className={className} />
           {styles}
          </div>
          

          這個新 API 可以將自定義樣式傳給子組件。

          由于這是 styled-jsx 的主要版本,如果你使用了 styles-jsx/css,那么在捆綁包大小方面有一個重大變化。在 styled-jsx 2 中,我們將生成外部樣式的“scoped”和“global”版本,即使只使用“scoped”版本,我們也會將“global”版本包含在內。

          使用 styled-jsx 3 時,全局樣式必須使用 css.global 而不是 css,這樣 styled-jsx 才能對包大小進行優化。

          App 和 Page 之間的 React Context(服務器端渲染)

          從 Next.js 7 開始,我們支持 pages/_app.js 和頁面組件之間的 React Context API。

          以前,我們無法在服務器端的頁面之間使用 React 上下文。原因是 Webpack 保留了內部緩存模塊而不是使用 require.cache,我們開發了一個自定義 Webpack 插件來改變這種行為,以便在頁面之間共享模塊實例。

          這樣我們不僅可以使用新的 React 上下文,在頁面之間共享代碼時還能減少 Next.js 的內存占用。


          社 區

          從 Next.js 首次發布以來,就已獲得相當多的用戶,從財富 500 強公司到個人博客。我們非常高興看到 Next.js 的采用量一直在增長。

          目前,超過 12,500 個被公開索引的域名在使用 Next.js。我們有超過 500 名貢獻者,他們至少提交過一次代碼。在 GitHub 上,這個項目已經有 29,000 個 star。自首次發布以來,已提交了大約 2200 個拉取請求。

          Next.js 社區在 spectrum.chat/next-js 上擁有近 2000 名成員。

          英文原文

          https://nextjs.org/blog/next-7


          主站蜘蛛池模板: 国产精品主播一区二区| 亚洲中文字幕无码一区| 亚洲精品一区二区三区四区乱码| 亚洲av午夜福利精品一区| 无码精品人妻一区二区三区漫画| 亚洲一区二区三区免费视频 | 无码国产伦一区二区三区视频| 国产福利91精品一区二区| 国产在线一区二区杨幂| 精品视频一区二区三区四区五区| 亚洲AV乱码一区二区三区林ゆな| 好爽毛片一区二区三区四无码三飞| 国产一区中文字幕| 色窝窝无码一区二区三区色欲 | AV天堂午夜精品一区| 色一乱一伦一图一区二区精品| 国产在线第一区二区三区| 国产精品无码一区二区三级| 男人的天堂av亚洲一区2区| 国产精品主播一区二区| 人妻无码一区二区三区免费 | 无码国产伦一区二区三区视频| 在线播放精品一区二区啪视频| 精品无码综合一区| 亚洲熟女www一区二区三区| 久久久久人妻一区精品果冻| 亚洲综合一区国产精品| 国产亚洲一区二区三区在线不卡 | 中文字幕精品一区二区三区视频| 麻豆aⅴ精品无码一区二区| 无码日韩精品一区二区人妻| 久久久精品人妻一区二区三区蜜桃| 国产精品视频免费一区二区三区| 亚洲国产成人一区二区精品区| 日韩一区二区免费视频| 久久综合亚洲色一区二区三区| 日韩十八禁一区二区久久| 无码福利一区二区三区| 中文字幕Av一区乱码| 日韩国产一区二区| 亚洲AV无码一区二区三区性色|