容颜武敌 發表於 2019-10-7 13:34:00

[Next] 二.next.js之组件

<h2 id="nextjs-中的组件">next.js 中的组件</h2>
<p>next.js 里面的组件(页面)就是 react 里面的组件.</p>
<h4 id="功能组件">功能组件</h4>
<p>在项目之中一个功能组件的创建 , 他可以和父组件放到一个文件里,也可以单独创建一个文件存放组件.</p>
<ul>
<li>没有生命周期</li>
<li>没有 this</li>
<li>没有 state 状态</li>
<li>一个函数就是一个组件</li>
</ul>
<p>功能组件一般作为展示类组件使用(轻,快)</p>
<pre><code>import fetch from 'isomorphic-unfetch'

function Page({ stars }) {
return &lt;div&gt;Next stars: {stars}&lt;/div&gt;
}

Page.getInitialProps = async ({ req }) =&gt; {
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
</code></pre>
<h4 id="类组件">类组件</h4>
<p>通过 class 和 extends 继承来的组件,就是类组件.组件内部包含状态(state)且状态随着事件或者外部的消息.类组件带有生命周期(lifecycle),用以在不同的时刻触发状态的更新.这种组件一般用来写业务逻辑,根据不同的业务场景组件的状态数量以及生命周期机制也不尽相同.但是在 next 中由于是服务端渲染好组件之后发送给客户端使用的,所有生命周期实际上是从 componentDidMount 开始的.</p>
<p>下面是一个类组件</p>
<pre><code>......

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 &lt;div&gt;Hello World {this.props.userAgent}&lt;/div&gt;
}
}

export default HelloUA
</code></pre>
<h4 id="getinitialprops">getInitialProps</h4>
<p>页面加载时加载数据,我们使用 getInitialProps 这种 async 静态方法.它可以异步获取数据并解析为 JavaScript Object 的形式添加到组件的 props 上.getInitialProps 服务器渲染时,将返回的数据进行序列化,类似于 JSON.stringify.确保返回的对象,是一个普通的 Object.对于初始页面加载,getInitialProps 仅在服务器上执行.getInitialProps 只有 在使用 Link 组件或使用路由 API 导航到其他路由时,才会在客户端上执行.</p>
<p>简单来说,初始化的请求一般放在服务端,页面显示在客户端之后的请求就放在客户端</p>
<ul>
<li>getInitialProps 不能在子组件使用.仅支持 pages 下的页面组件.</li>
<li>如果您使用某些仅用于服务器的模块 getInitialProps,不正确导入它们就会降低程序的速度.</li>
</ul>
<blockquote>
<ul>
<li>pathname -URL 的路径部分</li>
<li>query -URL 的查询字符串部分(对象)</li>
<li>asPath- String 在浏览器中显示的实际路径(包括查询)</li>
<li>req -HTTP 请求对象(仅服务器)</li>
<li>res -HTTP 响应对象(仅服务器)</li>
<li>err -渲染期间遇到任何错误的错误对象</li>
</ul>
</blockquote>
<h4 id="页面和动态页面">页面和动态页面</h4>
<p>页面和动态页面就是一个组件,next 通过在 pages 下创建 js 文件来自动将组件与路由之间的匹配完成,减少了路由绑定这一步操作.</p>
<h4 id="共享组件">共享组件</h4>
<p>共享组件就是公共组件,可以拿来复用的组件.一般我们在 components 文件夹下面创建这类组件,但是这与 pages 不同,并不是强制要求,你可以将你的共享组件在除 pages 之外的任何地方定义.</p>
<p>之前已经创建过 Header.js 和 MyLayout.js 两个布局,再新建一个 footer.js 组件,同时新建 components/layout 目录,将 3 个布局组件放进去</p>
<p>footer.js</p>
<pre><code>export default () =&gt; &lt;div className={["footer", "footer-main"]}&gt;&lt;/div&gt;;
</code></pre>
<p>MyLayout.js</p>
<pre><code>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 (
      &lt;div&gt;
      &lt;Header /&gt;
      &lt;div className={"content"}&gt;{children}&lt;/div&gt;
      &lt;Footer /&gt;
      &lt;/div&gt;
    );
}
}

export default Layout;

</code></pre>
<p>Header.js</p>
<pre><code>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 = (
&lt;Menu&gt;
    &lt;Menu.Item key="0"&gt;
      &lt;Link href="/"&gt;
      &lt;div&gt;
          &lt;Icon type="user" /&gt;
          我的主页
      &lt;/div&gt;
      &lt;/Link&gt;
    &lt;/Menu.Item&gt;
    &lt;Menu.Item key="1"&gt;
      &lt;Link href="/article"&gt;
      &lt;div&gt;
          &lt;Icon type="user" /&gt;
          我的专辑
      &lt;/div&gt;
      &lt;/Link&gt;
    &lt;/Menu.Item&gt;
    &lt;Menu.Item key="2"&gt;
      &lt;Link href="/about"&gt;
      &lt;div&gt;
          &lt;Icon type="user" /&gt;
          我的文章
      &lt;/div&gt;
      &lt;/Link&gt;
    &lt;/Menu.Item&gt;
    &lt;Menu.Divider /&gt;
    &lt;Menu.Item key="3"&gt;我的收藏&lt;/Menu.Item&gt;
    &lt;Menu.Item key="4"&gt;我的钱包&lt;/Menu.Item&gt;
    &lt;Menu.Item key="5"&gt;我的啥&lt;/Menu.Item&gt;
    &lt;Menu.Item key="6"&gt;我的啥&lt;/Menu.Item&gt;
    &lt;Menu.Divider /&gt;
    &lt;Menu.Item key="7"&gt;我的设置&lt;/Menu.Item&gt;
    &lt;Menu.Item key="8"&gt;退出&lt;/Menu.Item&gt;
&lt;/Menu&gt;
);

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

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

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

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

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

            &lt;div className="header-btn"&gt;
            &lt;Button type="danger" ghost shape="round" icon="edit" onClick={() =&gt; Router.push("/write")}&gt;
                写文章&gt;
            &lt;/Button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
      &lt;/div&gt;
    );
}
}
</code></pre>
<h4 id="windownagivatorlocalstorage-is-not-defined">window(nagivator,localStorage) is not defined</h4>
<ol>
<li>将代码从 componentWillMount()移至 componentDidMount() (但是大多数问题都不是这个)</li>
</ol>
<p>Next.js 是通用的,这意味着它首先在服务器端执行代码,然后在客户端执行代码.window 对象仅存在于客户端,因此,如果您需要在某些 React 组件中访问它,则应将该代码放在 componentDidMount 中.此生命周期方法仅在客户端上执行.</p>
<ol start="2">
<li>我一定要在 componentWillMount() 中执行</li>
</ol>
<pre><code>componentWillMount() {
    if (typeof window !== 'undefined') {
      console.log('window.innerHeight', window.innerHeight);
    }
}
</code></pre>
<ol start="3">
<li>不使用 ssr</li>
</ol>
<p>在使用富文本编辑器的时候出现这个问题,主要报错是在外部引入库中.</p>
<pre><code>const DynamicComponentWithNoSSR = dynamic(
() =&gt; import('../components/eidtor'),
{ ssr: false }
)

function Home() {
return (
    &lt;div&gt;
      &lt;Header /&gt;
      &lt;DynamicComponentWithNoSSR /&gt;
      &lt;p&gt;HOME PAGE is here!&lt;/p&gt;
    &lt;/div&gt;
)
}
</code></pre>
<ul>
<li>Window is not defined in NextJS React app?</li>
<li>with-no-ssr</li>
</ul>
<h2 id="再次发布">再次发布</h2>
<p>当前机器已经存在 now 工具 , 直接执行 now 命令</p>
<pre><code>now
</code></pre>
<p>输入网址,查看效果页面效果,需要注意的是 react-next-demo 和之前 next-demo 的区别,每次执行 now 之前需要修改项目名称,不然会自动覆盖前一个静态资源网站</p>
<h2 id="doc">Doc</h2>
<ul>
<li>官方 demo</li>
<li>获取数据和组件生命周期</li>
</ul><br><br>
来源:https://www.cnblogs.com/mybilibili/p/11630148.html
頁: [1]
查看完整版本: [Next] 二.next.js之组件