Next. Js Step on the pit entry series

  • Hello Next. Js
  • Add Antd && CSS
  • (3) Directory reconstruction && routing again
  • (4) Next. Js intermediate pit filling
  • (5) Introduce state management Redux
  • (6) Reconstruct the directory again
  • (7) Other relevant knowledge

Writing in the front

Had originally planned to at least a week, but recently things catch the thing all rounded up, project by the way, much of it moved once home, reminds me of a joke, a programmer in order not to long promised to the landlord the rent taught his children to learn programming ^_^ north drift is not easy, and line and cherish the hope every north bleaching programmers can freedom of wealth, as soon as possible If you’re too tired, move to another city

Fill in the pit

I still didn’t fill in the pit about routing in the last talk. Originally, PARams route thought it was no problem, but recently in the test, it was found that it was no problem when entering the system, but if the page of Params route is refreshed, a 404 page will be generated. So, keep fixing ~

// server.js server.get('/user/userDetail', (req, res) => { return app.render(req, res, `/user/userDetail/${req.query.username}`); }); server.get('*', (req, res) => { const parsedUrl = parse(req.url, true); const { pathname } = parsedUrl; if (typeof pathname ! == 'undefined' && pathname.indexOf('/user/userDetail/') > -1) { const query = { username: pathname.split('/')[3] }; return app.render(req, res, '/user/userDetail', query); } return handle(req, res); });Copy the code

The above is really ok, refresh the page without any problems ~

APP

Redux creates a globally unique store package in the outermost layer of the app. Redux creates a globally unique store package in the outermost layer of the app. Here’s an official example from Redux:

import React from 'react' import { render } from 'react-dom' import { Provider } from 'react-redux' import { createStore  } from 'redux' import todoApp from './reducers' import App from './components/App' let store = createStore(todoApp) render( <Provider store={store}> <App /> </Provider>, document.getElementById('root')Copy the code

The default is index, and the link is used in the component to jump to the router. This is a bit different from the traditional router. What to do? The official solution is apps, which can be used to bundle applications into a whole (forgive me if I take it that way).

We need to create a new _app.js file in the pages folder, sorry other names are not acceptable, and then write the following code to do it

// /pages/_app.js export default class MyApp extends App { render () { const {Component, pageProps} = this.props return ( <Container> <Component {... pageProps} /> </Container> ) } }Copy the code

Ok, that will do. We did nothing but add _app.js to the pages folder. We printed the router for props (we’ll use it later when we rebuild the page). So again, if you choose Next. Js, you need to follow its rules

Refactoring Layout

As mentioned in the previous several articles, the structure of the whole system is basically the upper and lower Layout. The top navigation bar is fixed, so a Layout component is removed. In this way, each new component needs to package a layer of Layout and manually upload the title to display it correctly. With the APP component we can refactor the Layout so that we don’t need to have a layer of Layout for each page

// constants. Js // Export const RouterTitle = {'/': 'home ', '/user/userList':' User list ', '/user/userDetail': 'User details'};Copy the code
// components/Home/Home.js import { Fragment } from 'react'; import { Button } from 'antd'; import Link from 'next/link'; const Home = () => ( <Fragment> <h1>Hello Next.js</h1> <Link href='/user/userList'> <Button Type ='primary'> </Button> </Link> </Fragment>); export default Home;Copy the code
// /pages/_app.js import App, {Container} from 'next/app'; import Layout from '.. /components/Layout'; import { RouterTitle } from '.. /constants/ConstTypes'; export default class MyApp extends App { constructor(props) { super(props); const { Component, pageProps, router } = props; this.state = { Component, pageProps, router }; } static getDerivedStateFromProps(nextProps, prevState) { if (nextProps.Component ! == prevState.Component || nextProps.pageProps ! == prevState.pageProps || nextProps.router ! == prevState.router) { return { Component: nextProps.Component, pageProps: nextProps.pageProps, router: nextProps.router }; } return null; } render () { const { Component, pageProps, router } = this.props; return ( <Container> <Layout title={RouterTitle[router.pathname]}> <Component {... pageProps} /> </Layout> </Container> ); }}Copy the code

Okay, that’s it for now, maybe the inside needs a little work. Anyway, the Layout part is pulled out. More and more standardized system appearance ~

Here’s a little bit of my feeling. Because Next did a lot of configuration for us, we had to follow its conventions when we wrote it, like routing, APP, static resources, etc. I think this writing has advantages and disadvantages, different people have different opinions, at least I am very like, because a problem to see the document will soon be solved, other self-configured SSR framework will vary from person to person appear various inexplicable bug, also don’t know how to solve ~

State management Redux ready

The React framework only focuses on the View layer, and many other things need to be added. Redux is a necessary part of the React application, so it becomes an integral part of the React family. Should also not too will have a good look at the react related knowledge, here only speak at Next. How to introduce in the js story and the story – saga, if like to use redux – thunk can use redux – thunk, but I don’t think thunk need to configure what, so I write the examples in saga). Same old thing, new thing introduced, need to be installed in advance

// Install redux-related dependencies yarn add redux redux-saga react-redux // Install the next.js dependency package for Redux yarn add next-redux-wrapper next-redux-sagaCopy the code

If you’re using a pure client SPA app (like create-React-app), then just install Redux and Redux-Saga, since we’re scaffolding it from next

Those who know redux know that store, Reducer, and Action work together to complete the state management mechanism of Redux. Since we chose to use Redux-saga to handle asynchronous functions, we also need a saga file. So let’s do it one by one:

store

// /redux/store.js import { createStore, applyMiddleware } from 'redux'; import createSagaMiddleware from 'redux-saga'; import rootReducer, { exampleInitialState } from './reducer'; import rootSaga from './saga'; const sagaMiddleware = createSagaMiddleware(); const bindMiddleware = (middleware) => { if (process.env.NODE_ENV ! == 'production') { const { composeWithDevTools } = require('redux-devtools-extension'); Const {logger} = require('redux-logger'); middleware.push(logger); return composeWithDevTools(applyMiddleware(... middleware)); } return applyMiddleware(... middleware); }; function configureStore (initialState = exampleInitialState) { const store = createStore( rootReducer, initialState, bindMiddleware([sagaMiddleware]) ); RunSagaTask = () => {store.sagatask = sagamiddleware.run (rootSaga); }; store.runSagaTask(); return store; } export default configureStore;Copy the code

To facilitate debugging, I introduced the Redux-Logger to print redux-related information during development.

As usual, THIS time I also use redux’s official simplest example Counter to simply implement, the final visual effect is shown below:

actions

// /redux/actions.js
export const actionTypes = {
  FAILURE: 'FAILURE',
  INCREMENT: 'INCREMENT',
  DECREMENT: 'DECREMENT',
  RESET: 'RESET',
};

export function failure (error) {
  return {
    type: actionTypes.FAILURE,
    error
  };
}

export function increment () {
  return {type: actionTypes.INCREMENT};
}

export function decrement () {
  return {type: actionTypes.DECREMENT};
}

export function reset () {
  return {type: actionTypes.RESET};
}

export function loadData () {
  return {type: actionTypes.LOAD_DATA};
}

Copy the code

reducer

import { actionTypes } from './actions'; export const exampleInitialState = { count: 0, }; function reducer (state = exampleInitialState, action) { switch (action.type) { case actionTypes.FAILURE: return { ... state, ... {error: action.error} }; case actionTypes.INCREMENT: return { ... state, ... {count: state.count + 1} }; case actionTypes.DECREMENT: return { ... state, ... {count: state.count - 1} }; case actionTypes.RESET: return { ... state, ... {count: exampleInitialState.count} }; default: return state; } } export default reducer;Copy the code

saga

The above two contents do not cover saga, because the simple Reudx counter does not involve asynchronous functions, so we need to request data ~ 😄 to use the advanced function of saga. There happens to be a user list page, and we’re using the following API to get an online user list data user data interface

/* global fetch */
import { all, call, put, take, takeLatest } from 'redux-saga/effects';


import { actionTypes, failure, loadDataSuccess } from './actions';

function * loadDataSaga () {
  try {
    const res = yield fetch('https://jsonplaceholder.typicode.com/users');
    const data = yield res.json();
    yield put(loadDataSuccess(data));
  } catch (err) {
    yield put(failure(err));
  }
}

function * rootSaga () {
  yield all([
    takeLatest(actionTypes.LOAD_DATA, loadDataSaga)
  ]);
}

export default rootSaga;

Copy the code

Then we initialize the data from the user list page as follows:

import { connect } from 'react-redux'; import UserList from '.. /.. /components/User/UserList'; import { loadData } from '.. /.. /redux/actions'; UserList.getInitialProps = async (props) => { const { store, isServer } = props.ctx; if (! store.getState().userData) { store.dispatch(loadData()); } return { isServer }; }; const mapStateToProps = ({ userData }) => ({ userData }); export default connect(mapStateToProps)(UserList);Copy the code

The truth out of this place in a fog, next, js react with original writing or some differences, status of container and show the container is not very clear, I temporarily use routing part to do container, anyway also successfully, in the next section to redraw the redux directory structure, strive to make the project more reasonable some ~

conclusion

I’m really sorry that it took a long time this time. Recently, my thoughts have been broken and I am not in the state of scientific research. Haha. I hope you will not be offended, and begin to calm down! Redux-saga is a redux-saga that can be used by next. Next, I thought about making the project directory more reasonable, and then I wrote several unified demos for everyone to demonstrate ~

The code address