[Next] 二.next.js之組件

next.js 中的組件

next.js 里面的組件(頁(yè)面)就是 react 里面的組件.

功能組件

在項(xiàng)目之中一個(gè)功能組件的創(chuàng)建 , 他可以和父組件放到一個(gè)文件里,也可以單獨(dú)創(chuàng)建一個(gè)文件存放組件.

  • 沒(méi)有生命周期
  • 沒(méi)有 this
  • 沒(méi)有 state 狀態(tài)
  • 一個(gè)函數(shù)就是一個(gè)組件

功能組件一般作為展示類組件使用(輕,快)

import fetch from 'isomorphic-unfetch'

function Page({ stars }) {
  return <div>Next stars: {stars}</div>
}

Page.getInitialProps = async ({ req }) => {
  const res = await fetch('https://api.github.com/repos/zeit/next.js')
  const json = await res.json()
  return { stars: json.stargazers_count }
}

export default Page

類組件

通過(guò) class 和 extends 繼承來(lái)的組件,就是類組件.組件內(nèi)部包含狀態(tài)(state)且狀態(tài)隨著事件或者外部的消息.類組件帶有生命周期(lifecycle),用以在不同的時(shí)刻觸發(fā)狀態(tài)的更新.這種組件一般用來(lái)寫(xiě)業(yè)務(wù)邏輯,根據(jù)不同的業(yè)務(wù)場(chǎng)景組件的狀態(tài)數(shù)量以及生命周期機(jī)制也不盡相同.但是在 next 中由于是服務(wù)端渲染好組件之后發(fā)送給客戶端使用的,所有生命周期實(shí)際上是從 componentDidMount 開(kāi)始的.

下面是一個(gè)類組件

......

import React from 'react'

class HelloUA extends React.Component {
  static async getInitialProps({ req }) {
    const userAgent = req ? req.headers['user-agent'] : navigator.userAgent
    return { userAgent }
  }

  render() {
    return <div>Hello World {this.props.userAgent}</div>
  }
}

export default HelloUA

getInitialProps

頁(yè)面加載時(shí)加載數(shù)據(jù),我們使用 getInitialProps 這種 async 靜態(tài)方法.它可以異步獲取數(shù)據(jù)并解析為 JavaScript Object 的形式添加到組件的 props 上.getInitialProps 服務(wù)器渲染時(shí),將返回的數(shù)據(jù)進(jìn)行序列化,類似于 JSON.stringify.確保返回的對(duì)象,是一個(gè)普通的 Object.對(duì)于初始頁(yè)面加載,getInitialProps 僅在服務(wù)器上執(zhí)行.getInitialProps 只有 在使用 Link 組件或使用路由 API 導(dǎo)航到其他路由時(shí),才會(huì)在客戶端上執(zhí)行.

簡(jiǎn)單來(lái)說(shuō),初始化的請(qǐng)求一般放在服務(wù)端,頁(yè)面顯示在客戶端之后的請(qǐng)求就放在客戶端

  • getInitialProps 不能在子組件使用.僅支持 pages 下的頁(yè)面組件.
  • 如果您使用某些僅用于服務(wù)器的模塊 getInitialProps,不正確導(dǎo)入它們就會(huì)降低程序的速度.
  • pathname -URL 的路徑部分
  • query -URL 的查詢字符串部分(對(duì)象)
  • asPath- String 在瀏覽器中顯示的實(shí)際路徑(包括查詢)
  • req -HTTP 請(qǐng)求對(duì)象(僅服務(wù)器)
  • res -HTTP 響應(yīng)對(duì)象(僅服務(wù)器)
  • err -渲染期間遇到任何錯(cuò)誤的錯(cuò)誤對(duì)象

頁(yè)面和動(dòng)態(tài)頁(yè)面

頁(yè)面和動(dòng)態(tài)頁(yè)面就是一個(gè)組件,next 通過(guò)在 pages 下創(chuàng)建 js 文件來(lái)自動(dòng)將組件與路由之間的匹配完成,減少了路由綁定這一步操作.

共享組件

共享組件就是公共組件,可以拿來(lái)復(fù)用的組件.一般我們?cè)?components 文件夾下面創(chuàng)建這類組件,但是這與 pages 不同,并不是強(qiáng)制要求,你可以將你的共享組件在除 pages 之外的任何地方定義.

之前已經(jīng)創(chuàng)建過(guò) Header.js 和 MyLayout.js 兩個(gè)布局,再新建一個(gè) footer.js 組件,同時(shí)新建 components/layout 目錄,將 3 個(gè)布局組件放進(jìn)去

footer.js

export default () => <div className={["footer", "footer-main"]}></div>;

MyLayout.js

import React, { Component } from "react";
import Header from "./Header";
import Footer from "./Footer";

import "../../asserts/css/styles.less";

class Layout extends Component {
  render() {
    let { children } = this.props;
    return (
      <div>
        <Header />
        <div className={"content"}>{children}</div>
        <Footer />
      </div>
    );
  }
}

export default Layout;

Header.js

import React, { Component } from "react";
import classnames from "classnames";
import { Menu, Button, Icon, Dropdown } from "antd";
import Link from "next/link";
import Router from "next/router";

const menu = (
  <Menu>
    <Menu.Item key="0">
      <Link href="/">
        <div>
          <Icon type="user" />
          我的主頁(yè)
        </div>
      </Link>
    </Menu.Item>
    <Menu.Item key="1">
      <Link href="/article">
        <div>
          <Icon type="user" />
          我的專輯
        </div>
      </Link>
    </Menu.Item>
    <Menu.Item key="2">
      <Link href="/about">
        <div>
          <Icon type="user" />
          我的文章
        </div>
      </Link>
    </Menu.Item>
    <Menu.Divider />
    <Menu.Item key="3">我的收藏</Menu.Item>
    <Menu.Item key="4">我的錢(qián)包</Menu.Item>
    <Menu.Item key="5">我的啥</Menu.Item>
    <Menu.Item key="6">我的啥</Menu.Item>
    <Menu.Divider />
    <Menu.Item key="7">我的設(shè)置</Menu.Item>
    <Menu.Item key="8">退出</Menu.Item>
  </Menu>
);

export default class Header extends Component {
  constructor(props) {
    super(props);

    this.state = {
      active: "home" //home article collect
    };
  }

  changeActive(active) {
    this.setState({
      active
    });
  }

  render() {
    return (
      <div className={"nav nav-main header"}>
        <div className={" header-inner"}>
          <div className={"header-content"}>
            <div className={"header-left"}>
              <div className={"logo"}>
                <img src="https://www.freelogodesign.org/Content/img/logo-samples/bakary.png" alt="logo"></img>
              </div>
            </div>
            <div className="header-menu">
              <div
                onClick={() => {
                  this.changeActive("home");
                }}
                className={classnames({
                  "header-menu-item": true,
                  active: this.state.active === "home"
                })}
              >
                <Link href="/">
                  <a>首頁(yè)</a>
                </Link>
              </div>
              <div
                onClick={() => {
                  this.changeActive("collect");
                }}
                className={classnames({
                  "header-menu-item": true,
                  active: this.state.active === "collect"
                })}
              >
                <Link href="/article">
                  <a>專輯</a>
                </Link>
              </div>
              <div
                onClick={() => {
                  this.changeActive("article");
                }}
                className={classnames({
                  "header-menu-item": true,
                  active: this.state.active === "article"
                })}
              >
                <Link href="/article">
                  <a>文章</a>
                </Link>
              </div>
            </div>

            <div className={"header-right"}>
              <Dropdown overlay={menu} trigger={["click"]} placement="bottomCenter">
                <div className={"avatar"}>
                  <img
                    src="https://images.xiaozhuanlan.com/photo/2019/2ad6384db0b94cd8e76d11194400df23.jpeg"
                    alt="avatar"
                  ></img>
                </div>
              </Dropdown>
            </div>

            <div className="header-btn">
              <Button type="danger" ghost shape="round" icon="edit" onClick={() => Router.push("/write")}>
                寫(xiě)文章>
              </Button>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

window(nagivator,localStorage) is not defined

  1. 將代碼從 componentWillMount()移至 componentDidMount() (但是大多數(shù)問(wèn)題都不是這個(gè))

Next.js 是通用的,這意味著它首先在服務(wù)器端執(zhí)行代碼,然后在客戶端執(zhí)行代碼.window 對(duì)象僅存在于客戶端,因此,如果您需要在某些 React 組件中訪問(wèn)它,則應(yīng)將該代碼放在 componentDidMount 中.此生命周期方法僅在客戶端上執(zhí)行.

  1. 我一定要在 componentWillMount() 中執(zhí)行
componentWillMount() {
    if (typeof window !== 'undefined') {
        console.log('window.innerHeight', window.innerHeight);
    }
}
  1. 不使用 ssr

在使用富文本編輯器的時(shí)候出現(xiàn)這個(gè)問(wèn)題,主要報(bào)錯(cuò)是在外部引入庫(kù)中.

const DynamicComponentWithNoSSR = dynamic(
  () => import('../components/eidtor'),
  { ssr: false }
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithNoSSR />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

再次發(fā)布

當(dāng)前機(jī)器已經(jīng)存在 now 工具 , 直接執(zhí)行 now 命令

now

輸入網(wǎng)址,查看效果頁(yè)面效果,需要注意的是 react-next-demo 和之前 next-demo 的區(qū)別,每次執(zhí)行 now 之前需要修改項(xiàng)目名稱,不然會(huì)自動(dòng)覆蓋前一個(gè)靜態(tài)資源網(wǎng)站

Doc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市徙垫,隨后出現(xiàn)的幾起案子苫纤,更是在濱河造成了極大的恐慌惯裕,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垛贤,死亡現(xiàn)場(chǎng)離奇詭異惦银,居然都是意外死亡绒窑,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)拷恨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)脖律,“玉大人,你說(shuō)我怎么就攤上這事腕侄⌒∪” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵冕杠,是天一觀的道長(zhǎng)微姊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)分预,這世上最難降的妖魔是什么兢交? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮笼痹,結(jié)果婚禮上配喳,老公的妹妹穿的比我還像新娘。我一直安慰自己凳干,他們只是感情好晴裹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著纺座,像睡著了一般息拜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上净响,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天少欺,我揣著相機(jī)與錄音,去河邊找鬼馋贤。 笑死赞别,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的配乓。 我是一名探鬼主播仿滔,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼惠毁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了崎页?” 一聲冷哼從身側(cè)響起鞠绰,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎飒焦,沒(méi)想到半個(gè)月后蜈膨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牺荠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年翁巍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片休雌。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡灶壶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出杈曲,到底是詐尸還是另有隱情驰凛,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布鱼蝉,位于F島的核電站洒嗤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏魁亦。R本人自食惡果不足惜渔隶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望洁奈。 院中可真熱鬧间唉,春花似錦、人聲如沸利术。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)印叁。三九已至被冒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轮蜕,已是汗流浹背昨悼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跃洛,地道東北人率触。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像汇竭,于是被迫代替她去往敵國(guó)和親葱蝗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子穴张,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容