React

Class component, function component

// class ArticleList extends React.Component {render() {// React element const {articles} = this.props; // All React components must protect their props as if they were pure functions. Return articles.map((item) => {const {title} = item; return <div> {title}</div>; }); }}Copy the code
// function component const ArticleList = (props) => {const {articles} = props; return articles.map((item) => { const { title } = item; return <div> {title}</div>; });Copy the code
const articles = [ { id: 1, title: 'Article 1' }, { id: 2, title: 'Article 2' }, { id: 3, title: 'Article 3' }, ]; Function App() {return <ArticleList/* component */ articles/* attribute, same as the name of the variables used by the sub-component to accept functions */={articles/* variable */} />; }Copy the code

1. Index.js calls render();

2.React calls the App component.

3. The App component passes the variable articles as props to the ArticleList component;

4. The ArticleList component uses the div structure as the return value;

5.React DOM Updates the page

Variable state inside a component

export default class Clock extends Component { constructor(props) { super(props); this.state = { date: new Date() }; } componentDidMount() {this.timerId = setInterval(() => this.tick(), 1000) after the component has been rendered into the DOM; } componentWillUnmount() {clearInterval(this.timerId); } tick() {this.setState({// Update component state date: new date (),}); } render() { return ( <div> <h1>Current Time: {this.state.date.toLocaleTimeString()}.</h1> </div> ); }}Copy the code

1. Call the Clock constructor to initialize this.state

2. Call the render method of the component to update the DOM

3. Call The componentDidMount() hook function, calling the Tick () method every second

4. Call setState() in the tick() method and rerender () with this.state.date changed

5. When the component is removed, call componentWillUnmount() and the timer stops

The controlled components

The React component that renders the form also controls what happens to the form during user input.

constructor(props){ super(props); this.state = { title: '', content: }} handleChange = (e) => {// Enter if (e.target.name === 'title') {this.setState({title: e.target.value }) } else if (e.target.name === 'content') { this.setState({ content: e.target.value }) } }; HandleSave = async () => {// save const {title, content} = this.state; if (title.length > 0 && content.length > 0) { console.log(title, content) } }; render() { const {title, content} = this.props; return ( <section> <h2>Add a New Post</h2> <form> <label htmlFor="title">Post Title:</label> <input type="text" id="title" name="title" value={title} onChange={this.handleChange} /> <label htmlFor="content">Content:</label> <textarea id="content" name="content" value={content} onChange={this.handleChange} /> <button type="button" className="button" onClick={this.handleSave}> Save Post </button> </form> </section> ); }Copy the code

Uncontrolled component

The form data is handed over to the DOM node for processing, and the component retrieves the form data using the REF

class AddPostForm extends React.Component{ constructor(props){ super(props); this.titleInput = React.createRef(); // createRef this.contentinput = react.createref (); } handleSave = async () => { const title = this.titleInput.current.value; const content = this.contentInput.current.value; if (title.length > 0 && content.length > 0) { console.log(title, content) } }; render() { return ( <section> <h2>Add a New Post</h2> <form> <label htmlFor="title">Post Title:</label> <input Type ="text" id="title" name="title" ref={this.titleInput} <textarea id="content" name="content" ref={this.contentInput} /> <button type="button" className="button" onClick={this.handleSave}> Save Post </button> </form> </section> ); }};Copy the code

Combinatorial usage of components

Components can reference other components in their output.

function Welcome(props) { return <h1>Hello, {props.name}</h1>; } function App() {return (<div> <Welcome name="Sara" />// pass name (string), This implements composition of components using <Welcome name="Cahal" /> <Welcome name="Edite" /> </div>); }Copy the code

State Hook

A Hook is a function that lets you “Hook” features like React state and lifecycle into a function component. A new way to manage state logic.

function AddPostForm(props){ const [title, setTitle] = useState(''); Const [content, setContent] = useState("); // 'useState' returns a pair of values: the current state and a function that lets you update it, which you can call in an event handler or some other place const handleChange = (e) => { if (e.target.name === 'title') { setTitle(e.target.value) } else if (e.target.name === 'content') { setContent(e.target.value) } }; const handleSave = async () => { if (title.length > 0 && content.length > 0) { console.log(title, content) } }; return ( <section> <h2>Add a New Post</h2> <form> <label htmlFor="title">Post Title:</label> <input type="text" id="title" name="title" value={title} onChange={handleChange} /> <label htmlFor="content">Content:</label> <textarea id="content" name="content" value={content} onChange={handleChange} /> <button type="button" className="button" onClick={handleSave}> Save Post </button> </form> </section> ); };Copy the code

Effect Hook

Const [articles, setArticles] = useState([]) useEffect(()=> {// Every time a component is rendered, Const fetchArticles = async () => {const response = await client.get('/fakeApi/posts'); Console. log(response) setArticles(response.posts); }catch(err){ console.error(err) } } fetchArticles(); }, []/* fetchArticles is executed only when the values in the array change. If the array is empty, the function executes once while the component is mounted.Copy the code

Custom Hooks

Extract component logic into reusable functions

Const [date, setCurrentDate] = useState(new date ()); const [date, setCurrentDate] = useState(new date ()); Const tick = ()=>{setCurrentDate(new Date())} useEffect(() =>{// 1000) return () => { clearInterval(timer) } }, []) return date; } export default function Clock() { const date = useCurrentDate(); return ( <div> <h1>Current Time: {date.toLocaleTimeString()}.</h1> </div> ); }Copy the code

A hook can only be called from a function component, a custom hook

Hooks can only be used in the top-level control flow of a function

React Router

<Router> <Navbar /> <div className="App"> <Switch> <Route exact path="/"> // When routes match, render corresponding components. Route defines a routing rule <Home /> </Route> <Route path="/editor"> < editor /> </Route> <Route path="/login"> < login /> </Route> <Post /> </Route> </Switch> </div> </Router>Copy the code

<Link to="/">Home</Link> Component Link Redirects routes

You can also do this through an imperative API call: history.push

UseHistory: Obtains the history object

UseParams: obtains route parameters

Redux

Redux basis

Store: Accesses global state and creates Store objects using configureStore. Store.getstate () gets the saved state of the store

Action: Describes the state change. It’s just a normal JS object. The type attribute must be included to describe state changes. The payload attribute represents the parameters contained in the action.

Dispatch: Sends an action and accepts an action as an argument.

Reducer: a function that calculates the new state based on the current application state and accepted actions. Must be pure functions (no side effects, can’t change state directly, integrate with immer library for effect)

Slice: A slice module contains all the logic (state, actions, Reducer, etc.) needed to manage a child state created through createSlice. Get the state from the useSelector function. Use useDispatch to change the state

Postslice Adds the slice of the article

import { createSlice } from '@reduxjs/toolkit'; const initialState = [ { id: '1', title: 'First Post!', content: 'Hello!' }, { id: '2', title: 'Second Post', content: 'More text' }, ]; Const postsSlice = createSlice({// create a slice name: 'posts', initialState,//slice's initialState reducers: AddPost (state, action) {state.push(action.payload); ,}}}); export const { addPost } = postsSlice.actions; export default postsSlice.reducer;Copy the code

Global Store

import { configureStore } from '@reduxjs/toolkit'; /postsSlice export default configureStore({// create a reduce-store object reducer) { posts }, });Copy the code

Redux entry for the Home component

import React from 'react'; import { useSelector } from 'react-redux'; import PostListComp from './components/PostList'; // A normal react component const Home = () => {const posts = useSelector((state) => state.posts <PostListComp posts={posts} /> </section>); }; export default Home;Copy the code

Redux entry for the Editor component

import React from 'react'; import { useDispatch } from 'react-redux'; import { nanoid } from '@reduxjs/toolkit'; import { useHistory } from 'react-router-dom'; import AddPostForm from './components/AddPostForm'; import { addPost } from '.. /.. /states/postsSlice'; const AddPost = () => { const dispatch = useDispatch(); // change state const history = useHistory(); Const handleSubmit = (data) => {// Submit event handler dispatch(addPost({... data, id: nanoid(), }), ); history.push('/'); }; return <AddPostForm onSubmit={handleSubmit} />; }; export default AddPost;Copy the code

Redux asynchronous

Thunk: A piece of code that delays execution

CreateAsyncThunk: API to create asynchronous execution

Const initialState = {posts: [],// posts: status: 'idle',// posts: status: null,}; Export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => { Const response = await client.get('/fakeApi/posts'); Return response.posts; }); export const addPost = createAsyncThunk( 'posts/addPost', async (initialPost) => { const response = await client.post('/fakeApi/posts', { post: initialPost }); return response.post; }); const postsSlice = createSlice({ name: 'posts', initialState, reducers: { // addPost(state, action) { // state.posts.push(action.payload); },}, extraReducers: {// Since fetchPosts are defined outside of postsSlice, use extraReducers instead of reducers [fetchposts.pending]: (state, action) => {// There is a fetchPosts request started to send state.status = 'loading'; Someday, [fetchPosts. Depressing]: (state, action) => {// The request is successful. state.posts = action.payload; }, [fetchpost.rejected]: (state, action) => {// State.status = 'failed'; state.error = action.error.message; }, [addPost.fulfilled]: (state, action) => { state.status = 'idle' }, }, });Copy the code

Not all state needs to be maintained in Redux. Error messages, loading, and so on are concerned at the component level. Redux has only one asynchronous action

const AddPost2 = () => { const dispatch = useDispatch(); const history = useHistory(); const [addRequestStatus, setAddRequestStatus] = useState('idle'); Loading const [error, setError] = useState(null); loading const [error, setError] = useState(null); const handleSubmit = async (data) => { try { setAddRequestStatus('pending'); const resultAction = await dispatch( addPost({ ... data, id: nanoid(), }), ); unwrapResult(resultAction); // Unpack resultAction to see if it is successful setAddRequestStatus('idle'); history.push('/'); } catch (err) {setError(err.message); setAddRequestStatus('idle'); }}; return ( <section> {addRequestStatus === 'pending' && <div className="loader">Loading... </div>} {error && <div className="error">{error}</div>} <AddPostForm onSubmit={handleSubmit} /> </section> ) };Copy the code

— Article details page module

Where is state on the article details page? Split slice for feature

const initialState = { data: null, status: 'idle', error: null, }; export const fetchPost = createAsyncThunk('post/fetchPost', Async (id) => {const response = await client.get(' /fakeApi/posts/${id} '); return response.post; }); export const addPostReaction = createAsyncThunk( 'post/addPostReaction', async ({ id, reaction }) => { const response = await client.post(`/fakeApi/posts/${id}/reaction`, { reaction, }); return response.post; }); const postSlice = createSlice({ name: 'post', initialState, reducers: { clearPost(state, action) { return initialState; }, }, extraReducers: { [fetchPost.pending]: (state, action) => { state.status = 'loading'; }, [fetchPost.fulfilled]: (state, action) => { state.status = 'succeeded'; state.data = action.payload; }, [fetchPost.rejected]: (state, action) => { state.status = 'failed'; state.error = action.error.message; }, [addPostReaction.fulfilled]: (state, action) => { state.data = action.payload; ,}}});Copy the code

Other status management schemes

RTK Query

Recoil

Context + Hooks