Next.js 实现 react 服务器端渲染

Next.js 实现 react 服务器端渲染

说明

实现 路由跳转、redux

重要文件版本

  • “next”: “^4.2.3”,
  • “react”: “^16.2.0”,
  • “react-dom”: “^16.2.0”

Next.js GitHub 文档

项目源码

使用

Next.js 使用文件体统作为API,可以自动进行服务器端渲染和代码分割

1. 安装

    yarn add next react react-dom

2. package.json 中添加 npm script

  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },

3. 创建 /pages 文件夹,其中文件会映射为路由

/pages 文件夹是顶级组件文件夹 其中 /pages/index.js 文件会映射文 / 路由,其他文件根据文件名映射

目录结构 映射路由
/pages/index.js /
/pages/about.js /about
/pages/home/index.js /home
/pages/home/about.js /home/about

每一个路由js文件都会 export 一个 React 组件,这个组件可以是函数式的也可以是通过集成 React.Component 得到的类

    export default () => <div>this is index page </div>;

4. 创建 /static 文件夹,存放静态资源

静态资源文件夹文件会映射到 /static/ 路由下,直接通过 http://localhost:3000/static/test.png 访问

5. 使用内置组件 <head> 定制每个页面的 head 部分

    import Head from 'next/head'; // 引入内置组件

    export default () => (
       <div>
          <Head>
             <title>index page</title>
             <meta name="viewport" content="initial-scale=1.0, width=device-width"/>
          </Head>
          <div>this is index page</div>
       </div>
    );
    import Link from 'next/link';

    export default () => (
       <div>
          <p>this is home index page</p>
          <Link href="/about">
             <a> to about page</a>
          </Link>
       </div>
    );

更多 Link 使用方式

import React, {Component} from 'react';
import Link from 'next/link';

export default class About extends Component {
   constructor(props) {
      super(props);
   }
   render() {
      // href 值可以是一个对象
      const href = {
         pathname: '/home',
         query: {name: 'test'}
      };

      return (
        <div>
           <p>this is about page </p>
           <img src="/static/test.png" alt="test"/>
           {/* replace 覆盖历史跳转 */}
           <Link href={href} replace>
            <a>click to home index page</a>
           </Link>
        </div> 
      );
   }
}

7. 使用内置 router 方法,手动触发路由跳转

next/router 提供一套方法和属性,帮助确认当前页面路由参数,和手动触发路由跳转

    import router from 'next/router';
    /*
        router.pathname  ==> /home
        router.query ==> {}
        router.route - 当前路由
        asPath - 显示在浏览器地址栏的实际的路由
        push(url, as=url) - 跳转页面的方法
        replace(url, as=url) - 跳转页面
    */

更好的方式使用路由 – router 的 withRouter 方法

扫描二维码关注公众号,回复: 2431928 查看本文章
import Link from 'next/link';
import {withRouter} from 'next/router';

const Home = (props) => {
    // 这里的 props 会得到 {router, url} 两个属性
    // router: {push: ƒ, replace: ƒ, reload: ƒ, back: ƒ, prefetch: ƒ, …}
    // url: {query: {…}, pathname: "/home", asPath: "/home?name=test", back: ƒ, push: ƒ, …}
   console.log(props);
   return (
      <div>
         <p>this is home index page </p>
         {/* <Link href="/about">
            <a> to about page</a>
         </Link> */}
      </div>
   );
}

export default withRouter(Home);

8. 使用 next-redux-wrapper 插件辅助实现 redux

1. 安装依赖

    sudo yarn add next-redux-wrapper redux react-redux redux-devtools-extension redux-thunk

2. 创建 initializeStore.js 一个可以返回 store 实例的函数

在这个文件中会完成装载中间件、绑定reducer、链接浏览器的redux调试工具等操作

    import { createStore, applyMiddleware } from 'redux';
    import { composeWithDevTools } from 'redux-devtools-extension'; 
    import thunk from 'redux-thunk';
    import reducer from '../modules/reducers';

    const middleware = [thunk];
    const initializeStore = initialState => {
       return createStore(
             reducer, 
             initialState, 
             composeWithDevTools(applyMiddleware(...middleware))
          );
    };

    export default initializeStore;

3. 创建 reducer , action

与普通 react-redux 项目创建 reducer, action 的方法一致,我把这部分代码都提取到一个名为 modules的文件夹中

    // /modules/reducers.js
    import { combineReducers } from 'redux';
    import about from './about/reducer';

    // 合并到主reducer
    const reducers = {
       about
    };

    // combineReducers() 函数用于将分离的 reducer 合并为一个 reducer 
    export default combineReducers(reducers);
   // /modules/about/reudcer.js 
   // /about 页面的 reducer
    import {
       CHANGE_COUNT
    } from '../types-constant';

    const initialState = {
       count: 0
    };

    const typesCommands = {
       [CHANGE_COUNT](state, action) {
          return Object.assign({}, state, { count: action.msg });
       },
    }

    export default function home(state = initialState, action) {
       const actionResponse = typesCommands[action.type];

       return actionResponse ? actionResponse(state, action) : state;
    }
    // /modules/about/actions.js
    // /about 页面的 action
    import {
       CHANGE_COUNT
    } from '../types-constant';

    export function changeCount(newCount) {
       return {
          type: CHANGE_COUNT,
          msg: newCount
       };
    }

4. 页面中使用

需要用到 next-redux-wrapper 提供的 withRedux 高阶函数,以及 react-redux 提供的 connect 高阶函数

    import React, { Component } from 'react';
    import withRedux from 'next-redux-wrapper';
    import { connect } from 'react-redux';
    import { bindActionCreators } from 'redux';
    import AboutCom from '../components/About/index';
    import initializeStore from '../store/initializeStore';
    import { changeCount } from '../modules/about/actions';

    class About extends Component {
       constructor(props) {
          super(props);
       }
       render() {
          const { about: { count }, changeCount } = this.props;
          return <AboutCom count={count} changeCount={changeCount} />;
       }
    }

    const connectedPage = connect(
       state => ({ about: state.about }),
       dispatch => ({
          changeCount: bindActionCreators(changeCount, dispatch)
       })
    )(About);

    export default withRedux(initializeStore)(connectedPage);

更多

查看 github官网

react-next github上一个next架构为主实现React服务端渲染的模板

猜你喜欢

转载自blog.csdn.net/mjzhang1993/article/details/79109349