函数组件和 class 组件的区别
- 纯函数,输入 props,输出JSX
- 没有实例,没有生命周期,没有 state
- 不能扩展其他方法
什么是受控组件?
- 表单的值受 state控制(状态驱动视图)
- 需要自行监听 onChange, 更新state
何时使用异步组件
- 加载大组件
- 路由懒加载
多个组件有公共逻辑,如何抽离
- 高阶组件(HOC)
- Render Props
- mixin 已经被 React 废弃
redux 如何进行异步请求
- 使用异步 action
- 如 redux-thunk
react-router 如何配置懒加载
- lazy(()=> import('component'))- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import React, { Suspense, lazy } from 'react'; const Home = lazy(() => import('./routes/Home')); const About = lazy(() = import('-/routes/About')); const App = () => ( <Router> <React.Suspense fallback={<div>loading</div>}> <Switch> <Router exact path="/" component={Home}/> <Route path="/about" component={About}/> </Switch> </React.Suspense> </Router> ); 
React.PureComponent作用
- 实现浅比较的 shouldComponentUpdate
- 性能优化
- 要结合不可变值使用
React 事件和 DOM 事件的区别
- 所有事件挂载到了 document上
- event不是原生的,是- SyntheticEvent合成事件对象
- dispatchEvent(- dispatchEvent方法接受一个事件对象作为参数,并在DOM元素上触发该事件)
React 性能优化
- 渲染列表是加 key
- 自定义事件、DOM 事件及时销毁
- 合理使用异步组件
- 减少函数 bind this 的参数
- 合理使用 SCUPureComponent和memo
- 合理使用 Immutable.js
- 通用的性能优化,如图片懒加载
React 和 Vue 的区别
不同点:
React使用JSX拥抱JS,Vue使用模版拥抱html
React函数式编程,Vue生明式编程
React更多需要自力更生,Vue把想要的都给你
相同点:
- 都支持组件化
- 都是数据驱动视图
- 都使用
vdom操作DOM
React Hooks 性能优化
- useMemo缓存数据
- useCallback缓存函数- useMemo- useCallback相当于 class 组件中的- SCU和- PureComponent
React Hooks 遇到哪些坑
- useState初始化值只能初始化一次- render:初始化- state
- re-render:只恢复初始化的- state值,不会再重新设置新的值,想要修改 只能使用- setState修改
 
- useEffect内部不能修改- state(解决方案推荐使用- useRef())
- useEffect依赖引用类型,会出现死循环(原理是:依赖项的比较是通过- Object.is({}, {})进行比较,当前两个对象比较返回的是- false, 如果是值类型会对比值的是否相同)
React Hooks 做组件逻辑复用的点
- 完全符合 Hooks原有规则,没有其他要求,易理解记忆
- 变量作用域很明确
- 不会产生组件嵌套的问题
JSX 本质
- React.createElement是- h函数,返回- vnode,然后通过- patch进行处理渲染
- 第一个参数可能是组件,也可能是 html tag标签。(区分组件与html写法是根据首字母的大小写,组件规定要首字母大小,html标签都是小写)
- 组件名称首字母必须大写(React 规定)1 2 3 4 5 6 7 8 9 10 11 12 // JSX 语法 const listElem = <div> <Input submitTitle={onSubmitTitle}/> <List list={list}/> </div> // 转化为`React.createElement` // const listElem = React.createElement("div", null, React.createElement(Input, { // submitTitle: onSubmitTitle // }), React.createElement(List, { // list: list // })); 
子组件暴漏方法给父组件调用
- React.forwardRef提供了一个强大的方法在组件中传递- ref,- forwardRef将父组件创建的- ref引用关联到子组件中任意元素
- useImperativeHandle定义要在组件中暴漏的数据和自定义方法,此方法接受两个参数:- ref和一个回调函数,回调函数返回一个对象(由父组件定义的- ref直接调用当前子组件件暴漏的方法)
使用代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 子组件 ChildComponent.js
import React, { forwardRef, useImperativeHandle } from 'react';
const ChildComponent = forwardRef((props, ref) => {
  const internalMethod = () => {
    console.log("Internal method called in child component");
    // 这里可以是子组件内部的逻辑
  };
  // 将自定义方法暴露给父组件
  useImperativeHandle(ref, () => ({
    callInternalMethod: internalMethod
  }));
  return (
    <div>
      {/* 子组件的其他内容 */}
    </div>
  );
});
export default ChildComponent;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 父组件 ParentComponent.js
import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
  // 创建一个 ref
  const childRef = useRef();
  // 在父组件中调用子组件的自定义方法
  const handleButtonClick = () => {
    if (childRef.current) {
      childRef.current.callInternalMethod();
    }
  };
  return (
    <div>
      <ChildComponent ref={childRef} />
      <button onClick={handleButtonClick}>Call Child Method</button>
    </div>
  );
};
export default ParentComponent;
class component使用ref是React.createRef()子类组件被调用自定义方法时,默认自定义方法就可以被父组件直接调用
fiber
fiber出现的背景,性能解决:
js是单线程,且和DOM渲染共用一个线程- 当组件足够复杂,组件更新时计算和渲染压力大
- DOM 操作需求(动画,鼠标拖拽)出现页面卡顿
- 将 reconciliation阶段进行任务拆分(commit无法拆分)
- DOM需要渲染时暂停,空闲时恢复 (- DOM什么时候需要渲染是通过- window.requestIdleCallback)
fiber 是 react 核心算法的一次重新实现,将原本同步的更新过程碎片化,避免主线程长时间的阻塞。
利用分片的思想,将耗时任务分成很多小片,每个小片执行完之后,把控制权交给 react 负责协调的模块,如果有紧急任务就优先处理,没有就继续更新。
一个更新过程,两个阶段:
第一阶段:找出需要更新的 DOM,这个阶段是可以被打断的 第二阶段:完成 DOM 的更新展示,这个阶段是不可以被打断的
useEffect 闭包陷阱
- React Hooks useEffect闭包陷阱
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function useEffectDemo() {
  const [value, setValue] = useState(0)
  useEffect(() => {
    setInterval(() => {console.log(value)}, 1000)
  }, [])
  function clickHandler() {
    setValue(value+1)
  }
  return (
    <div>
      value: {value} <button onClick={clickHandler}>increase</button>
    </div>
  )
}
// 输出结果为 0
useEffect依赖项为空数组时它只会执行一次console.log(value)获取的永远是一次渲染时初始化的state值,value发生变更时重新执行渲染
react 18 新特性
React 18的新特性包括:
- 并发渲染:React 18引入了并发渲染,这是一种新的后台机制,使React能够同时准备多个版本的UI¹²。并发渲染允许React在执行重渲染任务的过程中快速响应用户交互¹。 
- 自动批处理:React 18引入了自动批处理,这是一种性能改进,可以使用户界面开发过程更加流畅和响应¹²。 
- 新的API:React 18引入了一些新的API,如 - createRoot,- hydrateRoot,- renderToPipeableStream,- renderToReadableStream,以及一些新的Hooks,如- useId,- useTransition,- useDeferredValue,- useSyncExternalStore,- useInsertionEffect¹。
- 过渡:React 18引入了 - startTransitionAPI,这是一种新的API,可以帮助你保持应用的响应性¹²。
- 服务端的Suspense:React 18引入了服务端的Suspense,这是一种新的架构改进,可以提高渲染性能¹²。 
- 严格模式:在React 18中, - ReactDOM.render和- renderToString被弃用¹。
使用createRoot代替render。在你的index.js中,将ReactDOM.render更新为ReactDOM.createRoot来创建一个root,并使用root渲染你的应用¹。
fibar 与 react18 并发渲染 区别
React 18的并发渲染和React Fiber是两个不同的概念,但它们都是React的核心部分,用于优化UI的渲染。
React Fiber是 React 的核心算法的重新实现。Fiber 引入了一种新的调度机制,将渲染工作分解成更小的单元(称为“Fiber”),并根据其重要性为每个 Fiber 分配优先级³。高优先级的 Fiber(如用户输入和动画)会被优先处理,而低优先级的Fiber(如离屏更新)会被推迟处理,直到浏览器有空闲时间³。
React 18的并发渲染则是建立在Fiber基础之上的一种新的渲染模式。并发渲染允许 React 在执行重渲染任务的过程中快速响应用户交互。这是通过让渲染变得可中断来实现的:React 可以中断、暂停、恢复或放弃渲染。这种模式使得 React 可以同时准备多个版本的UI。
总的来说,React Fiber 是React的底层架构,用于优化渲染的调度,而React 18的并发渲染则是在此基础上,通过允许渲染的中断和恢复,来进一步提升应用的响应性和性能
useReducer 和 redux 的区别
- useReducer是- useState的代替方案,用于- state复杂变化
- useReducer是单个组件状态管理,组件通讯还需要- props
- redux是全局的状态管理,多组件共享数据
为什么要使用 Hooks
- 完善函数组件的能力,函数更适合 React 组件
- 组件逻辑复用,Hooks 表现更好
- 更好的状态管理,Hooks 可以更好的管理组件状态
