Next, js

Route map

The function of as, adding as after Link, can change the way the URL is displayed, but the original function does not change, the path optional modifier, this modifier will be displayed in the browser URL bar.

You can also use the as function in router.push, changing the second parameter in push

Nextjs actually does not change the file structure above, so direct access is not accessible to the path after AS changes the URL. Const handle = app.getrequesthandler ()

The Router of hook

There are six types of routed events, which are

const events = [
  'routerChangeStart'.'routerChangeComplete'.'routerChangeError'.'beforeHistoryChange'.'hashCahngeStart'.'hashChangeComplete'
]
function makeEvent(type){
  return (. args) = >{
    console.log(type,... args); } } events.forEach(event= >{
  Router.events.on(event,makeEvent(event))
})
Copy the code

HashChange is a jump with a #

HistoryChange is a jump without #

getInitialProps

This method is a NextJs-specific method that fetches data in the page and is called only by JS files in the Pages folder. This method is called on the server side without having to wait for the browser (client) to render. But the client will occasionally execute this code, and the client will execute it when the route redirects to the page. If you open the page directly, it’s server execution

const A= ({router,name}) = ><Link href="/test/test" as="test"><div><Button>123456</Button><Comp prop="132">123{router.query.id}+{name}</Comp></div></Link>
A.getInitialProps=() = >{
  return {  // Everything in the return is used by the A component as the props property of the A component
    name:'joke'}}Copy the code

Nextjs Custom app _app.js

import  App,{Container} from 'next/app'
import 'antd/dist/antd.css'
class myApp extends App{

  static async getInitialProps({Component,ctx}){// This method is called every time the page switches
    co
    let pageProps;
    if(Component.getInitialProps){
      pageProps = await Component.getInitialProps(ctx)
    }
    return {
      pageProps
    } 
  }

  render(){
    const {Component,pageProps} = this.props;
    console.log(Component);
    return(
      <Container>
        <Component {. pageProps} ></Component>
      </Container>)}}export default myApp
Copy the code

Custom _app.js also has a getInitialProps method, which passes in other components as arguments. The component also has getInitialProps inside, where the custom component is restored. If the component has the contents of a method called getInitialProps, it should return it for the component to use props, otherwise the component cannot accept props. The default app component does the same

Nextjs custom document

import Document,{ Html,Head,Main,NextScript } from 'next/document';
class MyDocument extends Document{

  static async getInitialProps(ctx){ // If the props are not overwritten, then the props should be returned
    const props = await Document.getInitialProps(ctx)
    return{... props} }render(){
    return (
      <Html>
        <Head>
          <style>
            {`.test {color:red}`}
          </style>
        </Head>
        <body className="test">
          <Main></Main>
          <NextScript></NextScript>
        </body>
      </Html>)}}export default MyDocument
Copy the code

Next defines the style

Local style

<style jsx>{A {color:blue}. Link {color:yellow} '}
</style>
Copy the code

Global style

<style jsx global> {A {color:blue}. Link {color:yellow}}
</style>
Copy the code

css-in-js

import Document, { Html, Head, Main, NextScript } from "next/document";
import { ServerStyleSheet } from "styled-components";
function withLog(Comp) {
  return props= > {
    console.log(props);
    return <Comp {. props} / >;
  };
}

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    // If the props are not overwritten, then the props should be returned
    const originalRenderPage = await ctx.renderPage;
    const sheet = new ServerStyleSheet();
    try {
      ctx.renderPage = () = > {
        return originalRenderPage({
          enhanceApp: App= > props= >
            sheet.collectStyles(<App {. props} ></App>)}); };const props = await Document.getInitialProps(ctx);
      return { ...props,style:<>{props.styles}{sheet.getStyleElement()}</> };
    } finally{ sheet.seal(); }}render() {
    return (
      <Html>
        <Head>
          <style>{`.test {color:red}`}</style>
        </Head>
        <body className="test">
          <Main></Main>
          <NextScript></NextScript>
        </body>
      </Html>); }}export default MyDocument;

Copy the code

Babelrc add the following configuration

react hooks

The function component added the ability to save state and update state via hooks, useState and useEffect via the API, respectively

UseReduce,useReduce is convenient to update the complex state

useState,useEffect

import React, { useState, useEffect, useReducer } from "react";

function MyCountFunction() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("jojo");
  // useEffect(() => {
  This callback is triggered when the // // component finishes rendering
  // const interval = setInterval(() => {
  // // setCount(2); // Set count to 2
  // setCount(c => c + 1); // We pass count as a parameter and update the count value to the result returned
  / /}, 1000);
  // return () => clearInterval(interval); // The returned function is called when the component is unloaded
  / /} []);
  useEffect(() = >{
    console.log('effect invoked')
    return () = >console.log('effect deteched'); }, [])// If name is passed, useEffect is triggered each time name changes, as is count
  return (
    <div>
      <span> {count} </span>
      <input type="text" value={name} onChange={e= > setName(e.target.value)} />
      <div>{name}</div>
    </div>
  );
}

function countReducer(state, action) {
  switch (action.type) {
    case "add":
      return state + 1;

    case "minus":
      return state - 1;

    default:
      returnstate; }}function ReduceCountComponent() {
  const [count, dispatchCount] = useReducer(countReducer, 0);
  useEffect(() = > {
    // This callback is triggered when the component finishes rendering
    const interval = setInterval(() = > {
      dispatchCount({ type: "add" });
    }, 1000);
    return () = > clearInterval(interval); // The returned function is called when the component is unloaded} []);return <span> {count} </span>;
}

export default MyCountFunction;

Copy the code

useref

UseRef enables function components to implement apis that only Component components can implement

usecontext

Just use the context to be the value

useCallback

const handleSearchChange = useCallback((event) = >{
    setSearch(event.target.value)
  },[setSearch]) // Since setSearch does not change, the array can be left blank
Copy the code

The purpose of useCallback is to use Memoize to reduce invalid re-render for performance optimization purposes. It’s the same old mantra, “Don’t optimize performance too early.” As a rule of thumb, it is important to observe and compare the results of these types of optimizations, because a callback in a small corner can cause the optimization to fail or even backfire.

redux

import { createStore } from 'redux';
const initialState = {
  count :0
}
const add = 'add'
function reducer(state = initialState,action){
  console.log(state,action);
  switch (action.type) {
    case add:
    return {count:state.count+1}
    default:
      return state
  }
}
const store = createStore(reducer,initialState)
store.dispatch({type:'add'})
store.subsribe(() = >{// This function is called every time data changes, and can update the state in React to re-render
  console.log(store.getState());
})
console.log(store.getState());

export default store
Copy the code

reducer

Instead of returning a plain literal, you should return an object in order to update the component

ConbineReducers,initialState should also be merged

import { createStore, combineReducers } from "redux";
const initialState = {
  count: 0
};
const add = "add";
function reducer(state = initialState, action) {
  console.log(state, action);
  switch (action.type) {
    case add:
      return { count: state.count + 1 };
    default:
      returnstate; }}function userReducer(state = { username: "zhangsan" }, action) {
  switch (action.type) {
    case "changeName":
      return { username: action.name };
    default:
      returnstate; }}const allReducer = combineReducers(reducer,userReducer)
const store = createStore(allReducer, {count:initialState,user: {username:'zhangsan'}});
store.dispatch({ type: "add" });
store.subsribe(() = > {
  // This function is called every time data changes, and can update the state in React to re-render
  console.log(store.getState());
});
console.log(store.getState());

export default store;

Copy the code

action

import { createStore, combineReducers,applyMiddleware } from "redux";
import ReduxThunk from 'redux-thunk'

const store = createStore(allReducer, {count:initialState,user: {username:'zhangsan'}},applyMiddleware(ReduxThunk));//applyMiddleware(ReduxThunk) allows asynchronous requests to be passed into action dispatchesStore.dispatch (asynchronous data);Copy the code
import { createStore, combineReducers,applyMiddleware } from "redux";
import ReduxThunk from 'redux-thunk'
const initialState = {
  count: 0
};
const add = "add";
function reducer(state = initialState, action) {
  console.log(state, action);
  switch (action.type) {
    case add:
      return { count: state.count + action.num || 1 };
    default:
      returnstate; }}function userReducer(state = { username: "zhangsan" }, action) {
  switch (action.type) {
    case "changeName":
      return { username: action.name };
    default:
      returnstate; }}function addSync(num){
  return (dispatch,getState) = >{ // The call to store.dispatch will pass in two arguments: dispatch,getState
    setTimeout(() = >{
      dispatch({type:'add',num})
    },1000)}}const allReducer = combineReducers({counter:reducer,user:userReducer})// Merge to pass in an object
const store = createStore(allReducer, {counter:initialState,user: {username:'zhangsan'}},applyMiddleware(ReduxThunk));//applyMiddleware(ReduxThunk) allows asynchronous requests to be sent to action dispatches. The second argument is a state object corresponding to the key of the first object
store.dispatch({ type: "add" });
store.dispatch({ username: "lisi".type:'changName' });
store.dispatch(addSync(5))
store.subscribe(() = > {
  // This function is called every time data changes, and can update the state in React to re-render
  console.log(store.getState());
});
console.log(store.getState());

export default store;

Copy the code

Asynchronous requests may have one warning below

react-redux

Redux was originally independent of React. Redux had a solution for connecting react

  1. Use provider in _app

  2. The purpose of a provider is to enable the elements wrapped under the provider to access the values provided in the provider, that is, the store

  3. How to use providers

    1. Introduce the CONNECT component in index

    2. In export default connect(component name) connect() returns a method and calls that method so it’s two parentheses

      export default connect(
        function mapStateToProps(state){
        return { // pass some state to props, which can be obtained at props
          count:state.counter.count,
          username:state.user.username
        }
      },function mapDispatchToProps(dispatch){
        return {
          add:(num) = >dispatch({type:'add',num}),// It is not recommended to use a string for type
          rename:(name) = >{dispatch({type:'changeName'.name:name})}
        }
      })(withRouter(A)) ;
      Copy the code
HOC =>{javascript export default (Comp)=>{ Return function TestHocComo({name,otherprops}){const name = name + 123; return <Comp {... otherprops} name={name}></Comp> } }Copy the code

Change props in redux

export default (Comp)=>{
  function TestHocComo({Component,pageProps,... rest}){ // When used with _app, you can receive Component pageProps
    // const name = name + 123;
    console.log(Component,pageProps);
    pageProps&&(pageProps.test=123)
    return <Comp Component={Component} pageProps={pageProps} {. rest} ></Comp>
  }
  TestHocComo.getInitialProps = Comp.getInitialProps
  return TestHocComo
}
Copy the code

This has the advantage of reducing the amount of code in Redux, reducing the coupling of the code, and simply wrapping the component around it instead of writing messy code inside it

Redux is integrated into Next

renderer

You can make one component have the style of another

layout.jsx

const Comp = ({ color, children, style }) = > (
  <div style={{ color.. style}} >{children}</div>
);
<Contaniner renderer={<div className="header-inner" />} ><div className="header-left">
            <div className="logo">{/ *<Icon type="github" />* /}<GithubOutlined style={IconStyle} />
            </div>
            <div>
              <Input.Search
                placeholder="Search the warehouse"
                value={search}
                onChange={handleSearchChange}
                onSearch={handleSearch}
              />
            </div>
          </div>
          <div className="header-right">
            <div className="user">
              <Avatar size={40} icon={<UserOutlined />} / ></div>
          </div>
</Contaniner>
<Content>
        <Contaniner
          //  comp="p"// The default tag passed in isp
          renderer={<Comp color="red" />}
        >
          {children}
        </Contaniner>
</Content>
      
Copy the code

Container.jsx

import {cloneElement} from 'react'
import { render } from 'react-dom'
const style = {
  width:'100%'.maxWidth:800.marginLeft:'auto'.marginRight:'auto'.paddingLeft:20.paddingRight:20
}
export default ({
  children,
  // comp: comp ='div', // accept the default component, destruct the assignment and change the parameter to uppercase
  renderer
})=>{
  return cloneElement(renderer,{
    style:Object.assign({},renderer.props.style,style),
    children
  })
  // return <Comp style={style}>{children}</Comp>
}
Copy the code

Is the renderer. Props. Style