React 理论知识
宏观设计:数据驱动视图
数据驱动视图
UI = render(data)
基础理解
React 中的组件通信方式
- props 和 callback
- context(跨层级)
- Event 事件
- ref 传递
- 状态管理
React 控制 render 渲染的方法
- 从父组件直接隔断子组件的渲染,经典的就是 memo,缓存 element 对象
- 组件从自身来控制是否 render ,比如:PureComponent ,shouldComponentUpdate

什么时候需要注意渲染节流
第一种情况数据可视化的模块组件(展示了大量的数据),这种情况比较小心因为一次更新,可能伴随大量的 diff ,数据量越大也就越浪费性能,所以对于数据展示模块组件,有必要采取 memo , shouldComponentUpdate 等方案控制自身组件渲染。
第二种情况含有大量表单的页面,React 一般会采用受控组件的模式去管理表单数据层,表单数据层完全托管于 props 或是 state ,而用户操作表单往往是频繁的,需要频繁改变数据层,所以很有可能让整个页面组件高频率 render 。
第三种情况就是越是靠近 app root 根组件越值得注意,根组件渲染会波及到整个组件树重新 render ,子组件 render ,一是浪费性能,二是可能执行 useEffect ,componentWillReceiveProps 等钩子,造成意想不到的情况发生。
强化组件的四种方式
- mixin 模式(已废弃)
- extends
- 高阶组件
- 自定义 hook
extends
// 新写的类组件中如果有同名的重写方法,会覆盖所被继承的类组件里的方法
class App extends React.Component {}高阶组件
import React, { useState } from "react";
import { Button } from "antd";
const HOC = (Component: any) => (props: any) => {
return <Component name={"harrison"} {...props}></Component>;
};
const Index: React.FC<any> = (props) => {
const [flag, setFlag] = useState<boolean>(false);
return (
<div>
<Button type="primary" onClick={() => setFlag(true)}>
获取props
</Button>
{flag && <div>{JSON.stringify(props)}</div>}
</div>
);
};
export default HOC(Index);React Hooks
useState
useState 有点类似于 PureComponent,它会进行一个比较浅的比较,这就导致了一个问题,如果是对象直接传入的时候,并不会实时更新
import { useState } from "react";
import { Button } from "antd";
const Index: React.FC<any> = () => {
const [state, setState] = useState({ number: 0 });
let [count, setCount] = useState(0);
return (
<>
<div>数字形式:{count}</div>
<Button
type="primary"
onClick={() => {
count++;
setCount(count);
}}
>
点击+1
</Button>
<div>对象形式:{state.number}</div>
<Button
type="primary"
onClick={() => {
state.number++;
setState(state);
}}
>
点击+1
</Button>
</>
);
};
export default Index;useEffect
副作用,这个钩子成功弥补了函数式组件没有生命周期的缺陷.
基本使用
useEffect(() => {
return destory;
}, deps);useContext
设置全局共享数据,使所有组件可跨层级实现共享。
基本使用
const contextValue = useContext(context);用法介绍
import { useState, createContext, useContext } from "react";
import { Button } from "antd";
const CountContext = createContext(-1);
const Child = () => {
const count = useContext(CountContext);
return (
<div style={{ marginTop: 10 }}>
子组件获取到的count: {count}
<Son />
</div>
);
};
const Son = () => {
const count = useContext(CountContext);
return <div style={{ marginTop: 10 }}>孙组件获取到的count: {count}</div>;
};
const Index: React.FC<any> = () => {
let [count, setCount] = useState(0);
return (
<>
<div>父组件中的count:{count}</div>
<Button type="primary" onClick={() => setCount((v) => v + 1)}>
点击+1
</Button>
<CountContext.Provider value={count}>
<Child />
</CountContext.Provider>
</>
);
};
export default Index;useReducer
useMemo
useCallback
useRef
useImperativeHandle
useImperativeHandle 是 React 中的一个 Hook,它允许你自定义由 ref 暴露出来的句柄。这通常与 forwardRef 一起使用,以便将 ref 传递给函数组件。使用 useImperativeHandle,你可以向父组件暴露自定义的 ref 句柄,例如,暴露你自己的命令式方法 。
在以下例子中,CustomInput 组件通过 useImperativeHandle 暴露了 focusInput 和 clearInput 方法给父组件 App。父组件就可以通过 ref 调用这些方法控制输入框的行为 。
import { forwardRef, useImperativeHandle, useRef } from 'react';
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef(null);
// 通过 useImperativeHandle 自定义 ref 句柄
useImperativeHandle(ref, () => {
return {
focusInput: () => {
inputRef.current.focus();
},
clearInput: () => {
inputRef.current.value = '';
},
};
}, []); // 依赖数组为空,意味着这个句柄在组件的整个生命周期中只会被创建一次
return <input ref={inputRef} {...props} />;
});
// 使用 CustomInput 组件
function App() {
const inputRef = useRef();
return (
<div>
<CustomInput ref={inputRef} type="text" />
<button onClick={() => inputRef.current.focusInput()}>Focus Input</button>
<button onClick={() => inputRef.current.clearInput()}>Clear Input</button>
</div>
);
}useLayoutEffect
useDebugValue
React API
useId
import React from 'react';
const id = React.useId();虚拟 DOM
React.createElement 计算出来的东西叫做虚拟 DOM,虚拟 DOM 仅仅是对真实 DOM 的一层描述而已。要想把虚拟 DOM 转换为真实 DOM,我们需要调用的是 ReactDOM.render()这个 API
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);fiber 架构
什么是 fiber
在 React16 以前,React 更新是通过树的深度优先遍历完成的,遍历是不能中断的,当树的层级深就会产生栈的层级过深,页面渲染速度变慢的问题,为了解决这个问题引入了 fiber,React fiber 就是虚拟 DOM,它是一个链表结构,返回了 return、children、siblings,分别代表父 fiber,子 fiber 和兄弟 fiber。
个人理解
fiber 是一种处理架构,也可以说是一种数据结构,承担着作为动态 element 到实际 dom 结构构建桥梁的作用;在实际上是使用 fiber 结构完成虚拟 DOM 的构建,再根据双缓冲树机制,进行深度遍历的一系列操作,完成 DOM 结构的更新。
组件设计
- 高阶组件 HOC
- render props
- 容器组件/展示组件
- 函数组件 + hooks
高阶组件
高阶组件
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。 具体而言,高阶组件是参数为组件,返回值为新组件的函数。 ——React 官方文档
function Hoc(Component) {
return class WrapComponent extends React.Component {
// 强化操作
render() {
return <Component {...this.props} />;
}
};
}render props
render props 模式和组合模式类似。区别不同的是,用函数的形式代替 children。函数的参数,由容器组件提供,这样的好处,将容器组件的状态,提升到当前外层组件中
export default function App() {
const aProps = {
name: "《React进阶实践指南》",
};
return (
<Container>{(cProps) => <Children {...cProps} {...aProps} />}</Container>
);
}性能优化手段
- shouldComponentUpdate
- memo
- getDerviedStateFromProps
- 使用 Fragment
- 使用正确的 key
- 拆分尽可能小的可复用组件,ErrorBoundary
- 使用 React.lazy 和 React.Suspense 延迟加载不需要立马使用的组件