Next.js 实现 react 服务器端渲染
说明
实现 路由跳转、redux
重要文件版本
- “next”: “^4.2.3”,
- “react”: “^16.2.0”,
- “react-dom”: “^16.2.0”
使用
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>
);
6. 使用内置组件 <Link>
进行路由跳转
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官网