本文阅读8分钟,喜欢的小伙伴可以持续关系小编哦
1. 什么是受控组件和非受控组件?
受控组件
像表单元素在用户输入时,像<input> <select>等元素需要绑定一个 change 事件,当组件的状态发生变化时就会触发 change 事件,更新组件的 state,这种就是受控组件。
非受控组件
如果一个表单组件没有 value、props 时,就可以称为非受控组件。 非受控组件可以使用 ref 来从 DOM 获取到表单的值。
2. 类组件和函数组件有什么区别?
- 类组件中存在生命周期函数,而函数组件中我们使用的是 hooks 来替代生命周期函数。
- 多次 render 时,类组件实际上只会 new 一次,函数组件会被调用多次。
- 心智模型上:函数式组件捕获了渲染所用的值;而类组件在读取 this 的时候,虽然 props 是不可变的,但是 this 是永远可变的,因此能在渲染方法或者生命周期方法中得到最新的实例。具体可参考:juejin.cn/post/684490…
3. state 和 props 的区别
state
state 时用来存储组件中的状态值,必须要使用 setState 来修改,state 值的变化会造成组件的重新渲染。
props
props 时一个外部传入到组件内的参数,具有可读性和不可变性,只能通过外部组件来传入新的 Props 来重新渲染子组件。
区别
- props 是不可修改的,state 是在组件中被创建,可以通过 setState 来进行修改的。
- props 是传递给组件的,state 则是组件自身内部管理的。
为什么 props 是只读的? 因为 React 的设计中,是根据单向数据流的设计模式,使状态可预测。如果子组件可以修改 props 的值,那么就会造成状态的不可预测性,给后续的维护及调试带来很大的困扰。
4. 父子组件的通信方式
- props 和 callback 方式父组件 -> 通过自身 state 改变,重新渲染,传递 props -> 通知子组件子组件 -> 通过调用父组件 props 方法 -> 通知父组件。
- ref 方式类组件可以通过 ref 直接获取组件实例,实现组件通信函数组件 forwardRef + useImperativeHandle 实现组件通信
- React-redux 或 React-mobx 状态管理方式状态管理库
- context 上下文方式将一些数据存储在全局数据中
- event bus 事件总线(类似于 PubSub 库)react 中并不推荐,因为需要手动绑定和解绑一定程度上违背了 React 数据流向原则小项目还好,大项目难以维护
5. 类组件的setState和函数组件的useState异同
相同点
都更新视图,底部调用了scheduleUpdateFiber方法,在事件驱动情况下都有批量更新规则。
不同点
- setState只要调用了就会执行更新;useState会浅比较2次state是否相同
- setState有专门监听变化的回调函数;useState只能通过useEffect
- setState底层处理上主要是和老的state合并;useState则重新赋值
6. 为什么React组件中 return 一个对象而不是一个元素时会报错
因为对象不具备迭代接口,必须要时原型或者自己身上有[Symbol.iterator]属性才可以,而数组是有迭代接口的,所以可以直接迭代。
7. 什么是 JSX
JSX 是一种表达式也是 React 的一种标准书写方式,允许我们使用书写 html 的方式去写 react 元素。
最终会变成什么
- jsx 元素节点首先会被 babel 编译成React.createElement形式
- createElement 处理之后,会被转换成 react element 对象。
- 在调和阶段,React element 对象的每一个子节点都会形成一个与之对应的 fiber 对象,然后通过 sibling、return、child 将每一个 fiber 对象联系起来。
babel工作原理
babel的一种工作原理(html 文件中 script 导入时):在 script 标签中,如果 type 不是text/javascript或者module,游览器不会去解析 javascript 内部的代码,babel 会监听全局的document.contentLoad(意味着当前页面所有的 script 标签全部生成完毕)。
babel 直接拿到所有的 script 标签,并读 script 上的属性getAttributes("type"),如果是text/babel,会把里面的代码全部拿过来,然后转换,生成新的 script 标签插入到页面。
8. 说说有哪些hooks
1. useState
用来声明状态变量,接受的参数是一个初始值;返回一个数组,数组的第[0]项是当前的状态值,[1]项是用来改变状态值的方法函数。
2. useEffect
副作用,react首次渲染和之后的每次渲染都可以调用一遍传给useEffect的函数,可以模拟类组件的3个生命周期:componentDidMount、componentDidUpdate、componentWillUnmount。
当第二个参数传入一个空数组时,相当于只在首次渲染的时候执行;如果传入一个变量,就会进行一次浅比较,变量发生变化时,会执行传入的函数。
3. useRef
- 可以获取当前元素的所有属性,并且返回一个可变的ref对象。
- 可以用来缓存数据
不是仅为真实 dom 服务,构建一个状态出来,但是这个状态时直接脱离 react 控制的,他的变化也不会造成重新渲染,同时状态还不会因为组件的重新渲染而被初始化
如果不使用 useRef 去处理真实 dom 会出现什么问题?
- 使用 state 会造成没必要的重新渲染,用全局变量又会造成闭包问题
4. useMemo(优化)
场景: 当一个父组件中调用了一个子组件的时候,父组件的 state 发生变化,会导致父组件更新,而子组件虽然没有发生改变,但也会进行更新。
- useMemo可以减少不必要的渲染和循环;
- 减少子组件的渲染次数;
- 同时通过特定的依赖进行更新,避免很多不必要的开销。
5. useCallback(优化)
与useMemo类似,useMemo返回的是函数运行的结果,useCallback返回的是函数。这个函数是父组件传递子组件的一个函数,防止做无关的刷新,这个组件必须配合memo来使用。
6. useContext
就是类组件中的context,可以用来存储一些全局的状态。
7. useReducer
是一个用于状态管理的hook api,与reducer函数相关。她接受2个参数,分别为reducer函数和初始状态。返回一个数组,第[0]项是state值,第[1]项是dispatch函数。
8. useLayoutEffect
和 useEffect 几乎完全一致,唯一的区别是 useLayoutEffect 会在所有的 dom 变更之后同步调用(意味着会完全阻塞后续工作),而 useEffect 是在所有的 dom 变更之后异步调用。
9. useTransition(react18,优化)
const [isPending, startTransition] = useTransition()是一个帮助我们在不阻塞UI的情况下更新状态。
返回1个数组,[0]项告诉我们是否存在待处理的transition;[1]项是一个startTransition函数,用这个方法可以把状态更新标记为transition。
js
复制代码
function TabContainer() { const [isPending, startTransition] = useTransition(); const [tab, setTab] = useState('about'); function selectTab(nextTab) { startTransition(() => { setTab(nextTab); }); } // …… }
....
更多建议查看React官网react.docschina.org/reference/r…
9.fowardRef
是一个高阶组件,接收一个组件作为参数返回一个新的组件。给函数组件扩展了一个 ref 属性。 给子组件挂 ref 是要要求子组件去追加一个 forwardRef 的,同时 forwardRef 会将得到的这个 ref 属性通过第二个参数传递给真实的函数组件。
10.useImperativeHandle
第一个参数是 ref,意味着在底层会去改这个 ref 的 current 属性 第二个参数是一个函数,这个函数的返回值最终会被丢到这个 ref.current 属性上去 第三个参数是依赖项,意味着依赖项不变的话 ref 的 current 值不会被重新赋值
11. React18有哪些更新
- setState自动批处理
- 17中只有react合成事件会进行批处理,legacy模式;
- 18中所有事件都进行批处理,提高了性能,concurrent模式。
- 支持并发模式的渲染
- 去掉了对IE浏览器的支持
- flushSync,用于退出批量更新
- react组件返回值更新
- 17中返回空组件只能返回null,返回undefined会报错
- 18中支持null和undefined
- 支持useId(在服务器和客户端生成相同的唯一一个id,避免hydrating的不兼容)
- 新增hooksuseInsertionEffect:只建议在css in js库中使用,在dom生成之前执行,在useLayoutEffect之前,一般用于提前注入脚本
- useSyncExternalStore:解决外部数据撕裂问题
- Suspense不再需要fallback捕获
- Concurrent Mode:并发模式,可以帮助应用保持响应,根据用户的设备性能和网速进行调整,通过渲染可中断来修复阻塞渲染机制。该模式下,可以同时更新多个状态;
- strict mode更新:使用严格模式时,React会对每个组件返回两次渲染,以便你观察一些意想不到的结果,在react17中去掉了一次渲染的控制台日志,以便让日志容易阅读。react18取消了这个限制,第二次渲染会以浅灰色出现在控制台日志 ....
12. Redux工作原理
场景
- 跨层级组件数据共享与通信
- 一些需要持久化的全局数据
工作原理
单例模式
主要构成
Store
全局状态管理对象
Reducer
一个纯函数,根据旧state和props更新state
Action
改变状态的唯一方式是调用dispatch函数,传递一个action给这个函数。