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
-
Use provider in _app
-
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
-
How to use providers
-
Introduce the CONNECT component in index
-
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