本篇文章内容迁移自老博客, 虽然写了很多年,但中间有调整或插入内容, 是对React基础知识点比较完善的梳理。
This article was written by English, due to I have learnt English for more than eight months, I don't want to forgot English, so I am rewritting it with English as my review.
What is React?
ReactNative, we can use React grammer to development native.virtual DOM and excellent Diff Algorithm,to reduce interaction of real DOM as much as possible.The comprise of React.
React Responsibe for logical control, data -> VDOMReactDOM render real DOM, VDOM -> DOMJSX
React uses JSX to describe UI@babel/preset-react has JSX transpile to JS Object, JSX -> React.creactElement(tagName, props, children)React.createElement gets this JS object build the vitual DOM which is needed by React.
JSX is one kind of JavaScript's grammer extension,It looks like a template language,But in fact it is completely implemented in JavaScript.JSX can describe UI friendly,it can effectively improve development experience.JSX is solely the syntactic sugar of React.cloneElement(component, props, ...children)The grammer rule of JSX
.引用React must in scope import React from 'react'props
class => classNamefor => htmlFor<components[props.storyType] />props is true
<Comp {...props} />babel who deal with it in compilationJSX 可以无缝融合到JS中
JSX can be assigned to variables, used as function parameters or returned as values.JSX, we can write JS logic, Such as conditions, switch, loop, statement.{} grammer of JSX
&&, If it returns true、false、null、undefined, the value will be ignored{{}} express an object, such as style={{ width: 100 }}key, in diff phase, compare type firstly, then compare key, so same grade and same type element,key must be uniqueCSSModule, the writing stylejsx/* index.module.css内容如下
.app {
.logo {
width: 100px;
}
}
*/
import styles from "./index.module.css";
const jsx = (
<div className={styles.app}>
<span
className={styles.logo}
style={{ width: "50px", height: "30px" }}
/>
</div>
);
css modules solely add necessary functions of web page development (local scope、global scope、custome hash、compse、define variable), You can see another article of mine CSS模块化方案
Component, It is similer to JavaScript function in concept. It can accept any parameter (like props), and return content which is used to describe UI
-- React element.
Component has two kinds: class Component and function Component.
Function components usually have no state, focus only on content display, return render outcome. From React 16.8, It added hooks, and the function component can own its states.
function Component is flexible, For example useEffect
jsxuseEffect(() => {
// equivalent to componentDidMount + componentDidUpdate
const timer = setInterval(() => {
setDate(new Date());
}, 1000);
return () => clearInterval(timer); // componentWillUnmount
},
[] // dependencies, which states change trigger the update? equivalent to shouldComponentUpdate
);
References: Hook introduce Hook video introduce
What is Hook?
Hook is a special function. It can link React's characteristic. For example. useState allows you add state and Hook in React function components.
When to use Hook?
When you write function components, and you realize to add some state, you must rewrite it in class, but now you can continue write in function component by use Hook.
Precautions
Hook in the outest of function, don't use it in loop, condition or sub function.React or custom Hook to call Hook.组件复合 - Composition
slot in VuesetState(updater[, callback])
this.setState({...}) shallow merge , similar to Object.assignthis.setState(state, (newState)=> {/* updated callback, equivalent to componentDidUpdate */})this.setState(currentState => { return newState;}) batch procession, it can avoid the situation of the variable is not the lastest value who caused by closure.javascript class App extends React.Component {
state = {
count: 0,
sex: '男'
}
add = () => {
// this.setState({count: this.state.count+1});
// this.setState({count: this.state.count+1});
// 此时 页面显示 1
this.setState(state => ({ count: state.count + 1 }));
this.setState(state => ({ count: state.count + 1 }));
// 现在页面显示2
}
render() {
return <h1 onClick={this.add}>{this.state.count}</h1>
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
Is setState synchronous or asynchronous?
< 18
React may combine multiple setState() calls into a single call. in synthetic events and lifecycle functions are asynchrnous. (synthetic events, it refers to one method calling another method, This asynchronous operation is actually a batch update.)> 18
ReactDOM.flushSyncPrecautions
Don't update the State directly, because it can't trigger the render of component!
Prior to react 15.5, react had built-in prop-types , later, prop-types was separated into its own type
the example of class component about type validation、required field validation、default value setting
jsxclass Person extends React.Component{
//对传给Person组件的props进行类型的限制
static propTypes = {
name: PropTypes.string, // 限制name必须为字符串类型
sex: PropTypes.string.isRequired,// 限制sex必须为字符串类型,且是必要属性
age: PropTypes.number,// 限制age必须为数值类型
address: PropTypes.string, // 限制address必须为字符串类型
}
//对传给Person组件的props进行默认值的设置
static defaultProps = {
address: '中国'
}
render(){
// return ...
}
}
// 下面的...p1,并不是原生ES8的对象解构,
// 而是babel+react环境提供的能力,支持展开运算符展开一个对象,
// 但是仅仅适用于传递标签属性!!
ReactDOM.render(<Person {...p1}/>,document.getElementById('test2'))
the example of function component about type validation、default value setting
jsxfunction Person(props){
const {name,age,sex,address} = props
// return ...
}
Person.propTypes = {
name: PropTypes.string,
sex: PropTypes.string.isRequired,
address: PropTypes.string,
}
Person.defaultProps = {
address: '中国'
}
//⚠️ Important Note: defaultProps will be deprecated in future versions of React.
// The React team recommends using default parameter syntax instead.
Three main properties of a component instance: ref、state、props
Three ways to use ref.
jsxclass Demo extends React.Component{
showData = ()=>{
const {input1} = this.refs
alert(input1.value)
}
render(){
return (
<div>
<input ref="input1" type="text" placeholder="点击按钮提示输入"/>
<button onClick={this.showData}>点我提示数据</button>
</div>
)
}
}
jsxclass Demo extends React.Component{
showData = ()=>{
const {input1} = this
alert(input1.value)
}
render(){
return (
<div>
<input ref={c => this.input1 = c} type="text" placeholder="点击按钮提示输入"/>
<button onClick={this.showData}>点我提示数据</button>
</div>
)
}
}
The value of
refis not redecleard when the component is refushed, It is specifically used to store component-level information.
There are three situations that React office recommended in which we can use it:
setTimeout/setInterval;

ReactDOM.render() --- first render
constructor()componentWillMount()render()componentDidMount() =====> commonly usedWe usually do some initialization tasks in this hook, for example:start timers、send network requests、subscribe to messages.
this.setSate() or parent component's render or this.forceUpdate()
shouldComponentUpdate() Notice:force updating not trigger shouldComponentUpdate (不走“阀门”).componentWillUpdate()render()componentDidUpdate()ReactDOM.unmountComponentAtNode()
componentWillUnmount() =====> commonly usedIt is used for cleanup tasks, such as closing timers and unsubscribing from messages.
super() in constructor and super(props).
super() in constructor, you will can't use this.props in constructor, so that we recommend super(props).jsclass MyComponent extends React.Component {
constructor(props) {
super(); // no props passed to parent constructor
console.log(this.props); // undefined here
console.log(props); // but props parameter is still available
}
}
componentWillReceiveProps
The version 17 deprecated three lifecycle functions, and it has replaced by getDerivedStateFromProps.
componentWillMountcomponentWillReceivePropscomponentWillUpdateIf you still want to use it , please add prefix of UNSAFE_
for example UNSAFE_componentWillMount
You also add it (the prefix of UNSAFE_) automatically through the command.
npx react-codemod rename-unsafe-lifecycles
Why is it marked as unsafe ?
Offical explanation
- These lifecycles are usually misunderstood and misused;
- Futhermore, we anticipate that their potential misuse issues may even greater in asyncronous rendering.
- We add the
UNSAFE_to those lifecycles in upcoming release. This is not refering to security, Instead, it indicates that code using that lifecycle methods may be likely to contain bugs in futher version of React, Especially after enabling asynchronous.
However, the specific bug was not discussed further. After checking the information, it was stated that.
constructor, because componentWillUnmout may not trigger(the willUnmount will only be triggered after the componentWillMount is triggered). If rendering is interrupted, causing willMount not be triggered, and the developer has added a listener in constructor, it will not be triggered when the component is destroyed, leading a memory leak.V16.4 add two new lifecycle functions:
static getDerivedStateFromProps(props, state)
render method is invoked, and it is also called during the initial mount and subsequent updates.state, if it return null, the state will not update, but render is also executed.UNSAFE_componentWillReceiveProps, The latter is only triggered when the parent component re-renders, not when setState is called internally.getSnapshotBeforeUpdate(prevProps, prevState)
render and before componentDidUpdate。componentDidUpdate(prevProps, prevState, snapshot).static getDerivedStateFromError
ComponentDidCatch
jsxclass ErrorLifePage extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) { // 副作用处理
// "组件堆栈" 例⼦:
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
console.error(info.stack)
}
static getDerivedStateFromError(error) {
// 更新 state 使下⼀次渲染可以显示降级 UI
return { hasError: true };
}
render() {
return (<div>
<h3>ErrorLifePage</h3>
{this.state.hasError ?
(<h1>Something went wrong.</h1>)
: (<Clock></Clock>)
}
</div>);
}
}
function Clock() {
const [date, setDate] = React.useState(new Date());
React.useEffect(() => {
const timer = setInterval(() => {
if(new Date().getMilliseconds() % 5 === 0) {
setDate('not Date');
}
setDate(new Date());
}, 1000);
return () => clearInterval(timer);
}, []);
return <h1>{date.toLocaleTimeString()}</h1>
}
Supplementary content: November second, 2025
onXxx attribute(注意大小写)
dispatchEvent(new CustomEvent('myClick', {detail: ...}))event.target.Three solutions to the problem of this binding
Notice
In JSX, the syntax of onClick={() => this.handleClick()} should be avoided.
Each render creates a different callback function. If this callback function is passed to a child component as a props, the child component will be re-render each time.
As mentioned earlier, React has a lifecyle method called shouldComponentUpdate, which return a boolean value to determine whether to excute render. This is key to performance optimization.
jsximport React, { Component, PureComponent } from 'react'
export default class PureCompUsage extends PureComponent {
constructor(props) {
super(props);
this.state = {
count: 1
}
}
handleClick = () => {
this.setState({
count: 10
})
}
render() {
// console.log('点击一次,这里会执行一次,其实count不变不需要重复渲染')
console.log('使用了PureComponent 对props和state进行浅比较,数据相同不会再次渲染')
return (
<>
<p>{this.state.count}</p>
<button onClick={this.handleClick}>ADD to 10</button>
</>
)
}
}
Thinking: If in function components, how to avoid the unnecessary render?
state, setState;props, we can use useMemo
const NewChild = React.memo(Child);useMemo can also be used to avoid complex calculations.Effect Hook
Effect Hook can let you execute side effects in function component.
for instance: data fetch, add subscribe and manually modifying the dom in react components. These are all considered side effects.
jsximport React, { useState, useEffect } from "react";
export default function UseEffectUsage() {
const [date, setDate] = useState(new Date().toLocaleTimeString());
useEffect(
() => {
// equivalent to componentDidMount and componentDidUpdate(the situations which has dependencies)
const timer = setInterval(() => {
setDate(new Date().toLocaleTimeString());
}, 1000);
// return equivalent to componentWillUnmount
return () => {
clearInterval(timer);
console.log('timer is cleared')
};
},
// dependencies, which state change will trigger updating
// equivalent to shouldComponentUpdate
[]
);
return <div>{date}</div>;
}
Custom hook
Sometimes we want to reuse some state,logic across component.
Currently, there are two main solutions to this problem: higher order components and render props.
Custom Hooks allow you to achieve the same goal without adding components.
Custom Hook is a function, Its name is start with 'use', other hook will be called inside the function.
hook-wrapped time case
jsimport React, { useState, useEffect } from "react";
export default function UseEffectUsage() {
const date = useClock();
return <div>{date}</div>;
}
function useClock() {
const [date, setDate] = useState(new Date());
useEffect(() => {
const timer = setInterval(() => {
setDate(new Date());
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
return date.toLocaleTimeString();
}
Hooks are functions of JavaScript. However, there are two additional rules for using them:
By passing the 'create' function and an array of dependencies as arguments to
useMemo, the memoized value is recalculated only when a dependency. This optimization helps to avoid high-overhead calculations in every render.
useMemo has two usages
jsx// 缓存某个计算结果,避免不必要的重复运算
import {useState, useMemo} from 'react';
export default function UseMemoUsage() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
/* const expensive = () => {
console.log("compute"); // 输入框 value 改变 也会触发
let sum = 0;
for (let i = 0; i < count; i++) {
sum += i;
}
return sum;
}; */
const expensive = useMemo(() => {
console.log("compute");
let sum = 0;
for (let i = 0; i < count; i++) {
sum += i;
}
return sum;
}, [count]); // 只有count改变才进行expensive计算;
return (
<div>
<p>{count} -- {expensive} </p>
<button onClick={() => setCount(count + 1)}>ADD</button>
<input type="text" defaultValue={text} placeholder='试试输入内容' onInput={e => {
setText(e.target.value)
}}/>
</div>
);
}
Supplementary content: November third, 2025
The React website has more detailed use cases for "useMemo".
- skipping expensive recalculations
- skipping re-redering of components
- preventing an effect from firing too much
- memoizing a dependency of another hook
- memoizing a function
Pass the inline callback function and an array of dependencies as arguments to
useCallback, and it will return amemoizedversion of the callback funtion, which will only be updated when a dependency changes. It is very useful when you pass an optimized child component that uses reference equality to advoid unnecessary rendering(such as shouldComponentUpdate).
Use case: When a child component triggers an event that requires calling a method in the parent component for calculation, this scenario typically involves the parent component passing the function to the child component via props. However this presents a problem: Change the parent component's state will cause the child component re-render, using useCallback can prevent this re-rendering of child component.
Let's look at a case:
setState will trigger the rendering of child componentjsxconst { useState, useCallback } = React;
function UseCallBackUsage() {
const [value, setValue] = useState({ text: "" });
console.log("父组件渲染");
const onChange = (e) => {
setValue({
text: e.target.value,
});
};
return (
<div>
<p>{value.text}</p>
<input
type="text"
placeholder="输入内容试试看"
value={value.text}
onChange={onChange}
/>
<hr />
<Child />
</div>
);
}
function Child(props) {
// 父组件setState会触发子组件渲染
console.log("子组件渲染");
return (
<div>
<span>子组件</span>
</div>
);
}
React.memo(Comp).

4.This is where useCallback comes in!

Precautions for use:
class component, then it must inherit from PureComponent.function component,then we should use React.memo() to wrap child componentjsximport React, {useReducer} from 'react';
export default function UseReducerUsage() {
function counter (state, action) {
switch(action.type) {
case 'ADD':
return state + 1;
default :
return state;
}
}
const [state, dispatch] = useReducer(counter, 0);
return <div>
<p>{state}</p>
<button onClick={() => dispatch({type: 'ADD'})}>ADD</button>
</div>
}
jsx// function component usage
import {useRef} from 'react';
export default function FuncRef () {
const inputRef = useRef();
return <div>
<input type="text" ref={inputRef}/>
<button onClick={handleClick}>focus</button>
</div>
function handleClick() {
inputRef.current.focus();
}
}
// class component usage
import React, { Component } from "react";
export class RefClassUasge extends Component {
constructor() {
super();
this.inputRef = React.createRef();
}
render() {
return <div>
<input type="text" ref={this.inputRef}/>
<button onClick={() => this.inputRef.current.focus()}>focus</button>
</div>
}
}
使用子组件Ref -- ref forward
jsximport React from "react";
export default function Forward() {
const ref = React.useRef();
return (
<div>
<MyInputW ref={ref} disabled placeholder="this is disabled input">
</MyInputW>
<button onClick={() => console.log(ref.current)}>get MyInputW</button>
</div>
);
}
const MyInput = (props, ref) => (
<input ref={ref} placeholder={props.placeholder} disabled={props.disabled}></input>
)
const MyInputW = React.forwardRef(MyInput);
通过ref暴露子组件的方法给父组件调用
jsximport React, { forwardRef, useImperativeHandle, useRef } from 'react'
export default function Expose() {
const exposeRef = useRef();
return (
<div>
<FancyInputW ref={exposeRef} />
<button onClick={() => {
exposeRef.current.focus();
}}>focus</button>
</div>
)
}
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus()
},
}));
return <input ref={inputRef} />
};
const FancyInputW = forwardRef(FancyInput);
The issue of useState failing to get the latest value.
jsximport React, { useState, useEffect } from 'react';
// export default function UseStateUsage () {
// const [arr, setArr] = useState([0]);
// useEffect(() => {
// console.log(arr);
// }, [arr]);
// const handleClick = () => {
// Promise.resolve().then(() => {
// setArr([...arr, 1]);
// }).then(() => {
// setArr([...arr, 2]); // 时赋值前 arr 为旧状态仍然为:[0]
// })
// }
// return <div>
// <button onClick={handleClick}>click</button>
// </div>
// }
// 解决方案1 setState(function)
// export default function UseStateUsage () {
// const [arr, setArr] = useState([0]);
// useEffect(() => {
// console.log(arr);
// }, [arr]);
// const handleClick = () => {
// Promise.resolve().then(() => {
// setArr((arr) => [...arr, 1]);
// }).then(() => {
// setArr((arr) => [...arr, 2]);
// })
// }
// return <div>
// <button onClick={handleClick}>click</button>
// </div>
// }
// 解决方案2 使用UseReducer模拟强制刷新
// export default function UseStateUsage() {
// const [,forceUpdate] = React.useReducer(x => x+1, 0);
// const [arr] = useState([0]);
// const handleClick = () => {
// Promise.resolve().then(() => {
// arr.push(1);
// }).then(() => {
// arr.push(2);
// forceUpdate();
// })
// }
// return <div>
// <h1>{arr.toString()}</h1>
// <button onClick={handleClick}>click</button>
// </div>
// }
// 解决方案3 ref
export default function UseStateUsage() {
const [arr, setArr, getArr] = useGetState([0]);
const handleClick = () => {
Promise.resolve().then(() => {
setArr([...getArr(), 1]);
}).then(() => {
setArr([...getArr(), 2]);
})
}
return <div>
<h1>{arr.toString()}</h1>
<button onClick={handleClick}>click</button>
</div>
}
const useGetState = (initVal) => {
const [state, setState] = useState(initVal);
const ref = React.useRef(initVal);
const _setState = (newVal) => {
ref.current = newVal;
setState(newVal)
}
const getState = () => {
return ref.current;
}
return [state, _setState, getState];
}
// reference https://www.cnblogs.com/hymenhan/p/14991789.html
When the parent component renders, the child component will also be rendered, how can we avoid unnecessary rendering of child components?
setState is called, there is no need to re-render DOM, this is where PureComponent comes in. It uses shouldComponentUpdate to perform a shallow comparison between props and state to determine whether to render or not.PureComponent can only be used in class component, so what about function component? We can use React.memo(Comp).useMemo cachinguseCallback, to prevent unnecessary rendering of child component which caused by the rendering of parent component (It needs to be used with memo)Use hooks to optimize code (similar to the Vue3 concept of separation of concerns).
Complete case study in this chapter click here
I've always been a vue 2 user, and Recently I've been learning react. I'm trying to compare the similarity and differences between the syntaxtix sugars of two frameworks in order to quickly master the basic usage of React.
react | vue2 | |
|---|---|---|
| 在线使用 | 支持 要使用React.createElement代替JSX | 支持 要引入含有编译器的包 |
| 官方文档 | https://react.docschina.org/ | https://cn.vuejs.org/v2/guide/ |
| cli 脚手架 | create-react-app 如果想像vue-cli一样灵活可以考虑umi | vue-cli 非常智能灵活,如 vue server sfc.vue运行组件vue creact project根据问卷生成脚手架vue ui图形化界面管理项目vue add package 智能安装依赖代码帮你处理好支持处理跨域、mock配置等 |
| devtools | https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi | https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd |
| 路由 | react-router | vue-router |
| 状态管理 | redux/react-redux mobx | vuex |
| 服务端渲染 | https://apollographqlcn.github.io/react-docs-cn/server-side-rendering.html | https://v3.cn.vuejs.org/guide/ssr/introduction.html |
| 原生开发 | react-native | weex |



本文作者:郭敬文
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!