边学边写nextjs-3 redux + 数据联动

1,185 阅读3分钟

到了redux状态管理后,感觉之前的目录都没发看了,所以重构一下吧。

重构

之前的目录结构有点乱,对于一个项目来说不是一个好事。不说多人合作,一个人维护也够呛。

redux安装跟前端一样

cnpm install --save redux react-redux

先看一下目录结构

-- root
    | -- src            // 模板等资源放在这里
        | -- components    // 模板
        | -- constants    // 常量
        | -- pages        // 路由
        | -- store        // reducer等存放
            | -- reducers    
            | -- actions    
            | -- index.js    // 入口
        | -- styles        // 公共css
    | -- static         // 静态资源
    | -- .babelrc
    | -- next.config.js
    | -- package.json

因为改动太大, 我就不一一把文件写出来了,挑几个重点的说下。

src目录

因为大部分前端框架都是从src开始的,而且next打包后会在根目录生成文件夹以及编译后的文件夹等等,如果全放到外面则会显得比较混乱。并且next是支持这样写的,会默认读取外层的pages,如果没有则会读取src里的pages。 还有一点,static是默认放静态资源的目录,如果需要,可以使用"/static/1.png"这样写。

_app.js

import React from 'react'
import { Provider } from 'react-redux'

import 'antd/dist/antd.css';
import '@/styles/style.scss';
import store from '@/store'

export default function MyApp({ Component, pageProps }) {
  return <Provider store={store}>
  			{/*这里可以加公共头信息*/}
			<Component {...pageProps} />
		</Provider>
}

如果需要加入公共的头部信息是可以写到以上注释部分的,比如

<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0,viewport-fit=cover">

适配手机端等,每个页面都需要的。

title,关键字等meta标签适配不同页面

比如a.js页面title是“这是a页面”,b.js页面title是“这是b页面”。这时_app.js改如何配置呢。

如果分别在各页面写Head,则会报错,只能在_app.js里写入头部。所以_app的props就起到作用了,可以获取到其他页面的模板和props。所以只需在_app.js里改写好就可。

// _app.js 标题如下

export default class MyApp extends Component {
	render () {
		const { Component, pageProps } = this.props;
		const { 
			m_title='有趣实用网——收藏各类好玩沙雕实用的网站', 
			m_description='收集各类,有趣、实用、新奇、沙雕、恶搞又好玩以及各类白嫖动漫,漫画的网站。',
			m_keywords='好玩,有趣,实用,有意思的网站,有趣的网站,好玩的网站,实用的网站,沙雕网站'
		} = pageProps;
		// console.log(pageProps)
	  return <Provider store={store}>
	    	<Head>
      		<title>{m_title}</title>
          <link rel="icon" href="/favicon.ico" />
          <meta name="baidu-site-verification" content="S6kx3QAdX2" />
          <meta name="sogou_site_verification" content="OTrlpJrfft"/>
          <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0,viewport-fit=cover" />
          <meta
            name="description"
            content={filterHTMLTag(m_description)}
          />
          <meta name="keywords" content={m_keywords} />
        </Head>
				<div id="root">
					<Header></Header>
					<div className="container main-content-wrapper">
						<Component {...pageProps} />
					</div>
				</div>
				<Loading />
				<Dialog />
				<AddWebSite isEdit={false} renderCb={ctx => eventBus.on('getAddSite#addSite', () => ctx) } />
				<AddWebSite isEdit={true} renderCb={ctx => eventBus.on('getEditSite#editSite', () => ctx) } />

	    </Provider>
	}
}

而其他页面的数据则在 getServerSideProps里添加 初始meta所需值

export async function getServerSideProps(context) {

  const { query: { id }, req } = context;

  const res = await axios.get(serverUrl+'/getSiteDetail', { params: { site_id: id }, headers: getServeAuthorization(req) }, )
  const data = res.data.result || {}

  return {
    props: {
      data, 
      m_title: data.name && '有趣实用网——' + data.name,
      m_keywords: data.name && (data.name+','+data.tags.join(',')),
      m_description: data.desc && data.desc
      // defaultList: res.data.result.list,
      // defaultTotal: res.data.result.total
    },
  }
}

import 使用@代表src目录

相信大家导入文件都习惯了@代表src目录,那样引入文件就可以不需要相对路径,特别是当前这么目录下,一个一个慢慢对比找相对路径就显得很麻烦,所以这里就单独抽出来。

先安装这个包

cnpm install --save-dev customize-cra

之后修改next.config.js

const path = require('path')
const withSass = require('@zeit/next-sass')
const withCss = require('@zeit/next-css');
const withPlugins = require("next-compose-plugins");
const { override, adjustStyleLoaders, addWebpackAlias } = require("customize-cra");

module.exports = withPlugins([withSass,withCss], {
  webpack: override(addWebpackAlias({
    '@': path.resolve('src'),
  }))
});

重启,ok完美运行。

这里就不放图了,git地址

github.com/NEOS55555/n…

数据联动

git地址跟上面一样,分支dataAcc

挑几个重点,新建了server文件夹,用于区分服务端的代码。

页面预渲染数据getServerSideProps

当一个页面在用户看到之前就应该有数据出来,则可以使用这个函数。emm也不知道这么解释对不对,就拿我那个页面来说,在用户进来之后,会等待很长一段时间,长时间的看loading。如果能在loading之前就把数据加载好,那就不会觉得等待很长。下面看getServerSideProps是如何使用的。

这个实在index.js里的部分代码

export async function getServerSideProps() {
  const res = await axios.get(url+'/test/list')
  const list = res.data.data;
  return {
    props: {
      list,
    },
  }
}

getServerSideProps这个函数只能放在pages下才会有效,子模块是不会生效的。形式固定

export async function getServerSideProps() {

  return {
    props: {

    },
  }
}

不可改变大体结构。具体的坑点还无法得知,毕竟没有开始正式写代码,只是大致的体验了一把,还是蛮不错的。