当前位置:   article > 正文

React面试题_react18面试题

react18面试题

1、react18有那些更新?

1. setState自动批处理

setState在16.4版本之前都是同步的,在16版本之后基本都是异步的除了一些特殊事件(原生js、promise、setTImeout、setInterval)

      • v17只有react事件进行批处理(原生js、promise、setTImeout、setInterval都不会)
      • v18所有事件都进行批处理,多次调用setState,会合并成一次
2. 组件返回值更新
      • v17 return null undefined 报错
      • v18 支持 null undefined 返回
3. 严格模式支持
      • 严格模式可以被认为是 "use strict" 表示
      • 排查问题:
        • 使用不安全的生命周期方法的警告
          • componentWillMount、componentWillReceiveProps 和 componentWillUpdate
          • 需要加上不安全前缀 UNSAFE_componentWillMount
        • 推荐使用createRef API而不是传统字符串ref
        • 检查意外副作用
          • 在开发模式中调用hooks会调用两次,可能会在调试代码时造成一些混乱,严格模式确保检查潜在的内存泄漏
        • 元素卸载和重新挂载,每个元素都会进行,前后状态和效果与元素第一次挂载时相同
4. hooks
      • useInsertionEffect 它可以在元素插入到DOM中时应用过渡效果,例如淡入、滑动等效果,使页面变得更加生动和吸引人
      • useLayoutEffect 在useEffect之前执行,允许在运行时动态地注入样式,及时注入(保证了在任何布局效果触发之前插入样式,减少了样式的重复计算和布局抖动);
5. concurrent mode(并发模式):

Concurrent模式想做到的事情就是用户可以自定义更新任务优先级并且能够通知到React,React再来处理不同优先级的更新任务,当然,优先处理高优先级任务,并且低优先级任务可以中断

6. flushSync:

中断批处理,批处理是一个破坏性改动,如果你想退出批量更新,你可以使用 flushSync,建议尽量不要这么做

2、jsx是什么和js有什么区别,为什么要使用jsx?

定义:

JSX 是 JavaScript 语法的扩展,它允许编写类似于 HTML 的代码。JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式

jsx语法可以转换为js形式

  1. // jsx形式
  2. <div className="sidebar" />
  3. // js形式
  4. React.createElement( 'div', {className: 'sidebar'})
作用:

React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据

转换为真实dom的过程
    • 使用React.createElement或JSX编写React组件,实际上所有的 JSX 代码最后都会转换成 React.createElement(…) ,Babel帮助我们完成了这个转换的过程。
    • createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
    • ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM

3、react生命周期?

旧:

组件挂载:
    • 组件挂载时(组件状态的初始化,读取初始 state 和 props 以及两个生命周期方法,只会在初始化时运行一次)
      • componentWillMount 会在 render 之前调用(在此调用 setState,是不会触发 re-render 的,而是会进行 state 的合并。因此此时的 this.state 不是最新的,在 render 中才可以获取更新后的 this.state。)
      • componentDidMount 会在 render 之后调用
组件更新(state和props):
    • 组件更新时(组件的更新过程是指父组件向下传递 props 或者组件自身执行 setState 方法时发生的一系列更新的动作)
      • 组件自身的 state 更新,依次执行
        • shouldComponentUpdate(会接收需要更新的 props 和 state,让开发者增加必要的判断条件,在其需要的时候更新,不需要的时候不更新。如果返回的是 false,那么组件就不再向下执行生命周期方法。)
        • componentWillUpdate
        • render(能获取到最新的 this.state)
        • componentDidUpdate(能获取到最新的 this.state)
      • 父组件更新 props 而更新
        • componentWillReceiveProps(在此调用 setState,是不会触发 re-render 的,而是会进行 state 的合并。因此此时的 this.state 不是最新的,在 render 中才可以获取更新后的 this.state。
        • shouldComponentUpdate
        • componentWillUpdate
        • render
        • componentDidUpdate
组件卸载
    • 组件卸载时
      • componentWillMount(我们常常会在组件的卸载过程中执行一些清理方法,比如事件回收、清空定时器)
新:

getDerivedStateFromProps:

在每次render方法前调用,第一个参数为即将更新的props,第二个参数为上一个状态的state,可以比较props 和 state来加一些限制条件,防止无用的state更新

该方法需要返回一个新的对象作为新的state或者返回null表示state状态不需要更新

getSnapshotBeforeUpdate:

render之后执行

接收两个参数:prevProps(表示更新前的props)和prevState(表示更新前的state)。它的返回值将作为第三个参数传递给componentDidUpdate方法。

不能直接操作DOM,因为DOM尚未更新

4、react事件机制与原生事件的区别?

React基于浏览器的事件机制自身实现了一套事件机制,包括事件注册、事件的合成、事件冒泡、事件派发等这套机制被称之为合成事件;

合成事件是 React模拟原生 DOM事件所有能力的一个事件对象;根据 W3C规范来定义合成事件,兼容所有浏览器,拥有与浏览器原生事件相同的接口

  • 事件名称命名方式不同
  1. // 原生事件绑定方式
  2. <button onclick="handleClick()">按钮命名</button>
  3. // React 合成事件绑定方式
  4. const button = <button onClick={handleClick}>按钮命名</button>
  • 事件处理函数书写不同
  1. // 原生事件 事件处理函数写法
  2. <button onclick="handleClick()">按钮命名</button>
  3. // React 合成事件 事件处理函数写法
  4. const button = <button onClick={handleClick}>按钮命名</button>
执行顺序
  • 会先执行原生事件,因为React只有触发时所有事件才会挂载在 document 对象上
  • 当真实 DOM 元素触发事件,会冒泡到 document 对象后,再处理 React 事件
  • 所以会先执行原生事件,然后处理 React 事件
  • 最后真正执行 document 上挂载的事件

5、react中props和state的区别?

props 是传递给组件的(类似于函数的形参),而 state 是在组件内被组件自己管理的(类似于在一个函数内声明的变量)

props 是不可修改的,所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

state 是在组件中创建的,一般在 constructor中初始化 state, state 是多变的、可以修改,每次setState都异步更新的

6、react中keys的作用?

Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。

在 React 中渲染集合时,向每个重复的元素添加关键字对于帮助React跟踪元素与数据之间的关联非常重要。key 应该是唯一ID,最好是 UUID 或收集项中的其他唯一字符串

注意事项:

    • key 应该是唯一的
    • key不要使用随机值(随机数在下一次 render 时,会重新生成一个数字)
    • 使用 index 作为 key值,对性能没有优化

7、react中refs的作用?

Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄。

我们可以为元素添加 ref 属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回

  1. class CustomForm extends Component{
  2. handleSubmit = () => {
  3. console.log("Input Value: ", this.input.value)
  4. }
  5. render () {
  6. return (
  7. <form onSubmit={this.handleSubmit}>
  8. <input type='text' ref={(input) => this.input = input} />
  9. <button type='submit'>Submit</button>
  10. </form> ) }
  11. }


上述代码中的 input 域包含了一个 ref 属性,该属性声明的回调函数会接收 input 对应的 DOM 元素,我们将其绑定到 this 指针以便在其他的类函数中使用

8、受控组件和非受控组件?

受控组件:

渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”;一般用于表单元素(<input>、 <textarea> 和 <select>等)

  1. class TestComponent extends React.Component {
  2. constructor (props) {
  3. super(props);
  4. this.state = { username: 'lindaidai' };
  5. }
  6. render () {
  7. return <input name="username" value={this.state.username} />
  8. }
  9. }
非受控组件:

简单来讲,就是不受我们控制的组件,一般情况是在初始化的时候接受外部数据,然后自己在内部存储其自身状态

  1. // An highlighted block
  2. import React, { Component } from 'react';
  3. export class UnControll extends Component {
  4. constructor (props) {
  5. super(props);
  6. this.inputRef = React.createRef();
  7. }
  8. handleSubmit = (e) => {
  9. console.log('我们可以获得input内的值为', this.inputRef.current.value);
  10. e.preventDefault();
  11. }
  12. render () {
  13. return (
  14. <form onSubmit={e => this.handleSubmit(e)}>
  15. <input defaultValue="lindaidai" ref={this.inputRef} />
  16. <input type="submit" value="提交" />
  17. </form>
  18. )
  19. }
  20. }
应用场景:

9、函数组件和类组件的区别?

类组件:

顾名思义,也就是通过使用ES6类的编写形式去编写组件,该类必须继承React.Component

如果想要访问父组件传递过来的参数,可通过this.props的方式去访问;在组件中必须实现render方法,在return中返回React对象

  1. class Welcome extends React.Component {
  2. constructor(props) {
  3. super(props)
  4. }
  5. render() {
  6. return <h1>Hello, {this.props.name}</h1>
  7. }
  8. }
函数组件:

函数组件,顾名思义,就是通过函数编写的形式去实现一个React组件,是React中定义组件最简单的方式;函数第一个参数为props用于接收父组件传递过来的参数

  1. function Welcome(props) {
  2. return <h1>Hello, {props.name}</h1>;
  3. }
区别:
代码
      • 直观区别,函数组件代码量较少,相比类组件更加简洁
this指向
    • 函数组件看似只是一个返回react元素的函数,其实体现的是无状态组件的思想,函数组件中没有this, 没有state,也没有生命周期,这就决定了函数组件都是展示性组件,接收props,渲染dom,而不关注其他逻辑
生命周期
    • 因为函数组件不需要考虑组件状态和组件生命周期方法中的各种比较校验,所以有很大的性能提升空间

10、react Fiber架构是什么?可以做什么?

定义

fiber架构是react16引入的新型框架,Fiber是 React内部所定义的一种数据结构,它是 Fiber树结构的节点单位,也就是 React 16 新架构下的虚拟DOM

作用
    • 为每个任务增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
    • 增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
    • dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行
解决的问题:

1.更好的用户体验:通过使用Fiber架构,React应用程序可以在用户交互事件发生时立即响应,避免了页面卡顿和无响应的情况。

2.增量渲染:Fiber架构将渲染过程划分为多个任务单元,可以根据任务的优先级和时间片进行调度,使得渲染工作可以分布在多个帧中完成,提高了页面的渲染性能。

3.可中断、恢复的机制:Fiber架构允许React在执行渲染任务时进行中断,并在有空闲时间时恢复任务,使得渲染过程可以更好地适应浏览器的调度。

4.更好的错误边界和组件的并发处理:Fiber架构为React引入了新的错误处理机制,可以更好地捕获和处理组件中发生的错误,同时也为React未来支持并发模式奠定了基础。

11、react和vue的区别?

共同点:

都支持组件化

都是数据驱动视图

都是vdom操作dom

都支持模块化

不同点:

react是用于搭建UI界面的javascript库,vue是渐进式框架

react是单向数据流,vue是双向数据绑定

react使用jsx语法,vue使用接近html语法

react拥有更庞大和成熟的生态系统,拥有大量的第三方库和工具,vue相对来说比较少

react更适合大型和复杂的应用程序,使用起来更具灵活性和扩展性,vue则适合快速原型开发和小型项目,更容易上手

12、react组件如何通信?

  • 父组件向子组件传递
    • 父组件在调用子组件的时候,只需要在子组件标签内传递参数,子组件通过props属性就能接收父组件传递过来的参数
  1. // 父组件
  2. const element = <EmailInput email="123124132@163.com" />;
  3. // 子组件
  4. function EmailInput(props) {
  5. return (
  6. <label>
  7. Email: <input value={props.email} />
  8. </label>
  9. );
  10. }
  • 子组件向父组件传递
    • 子组件向父组件通信的基本思路是,父组件向子组件传一个函数,然后通过这个函数的回调,拿到子组件传过来的值
  • 兄弟组件之间的通信
    • 子组件传递父组件,父组件传递子组件;
  • 父组件向后代组件传递
    • context上下文
      • 1.通过createContext创建上下文
  1. const PriceContext = React.createContext('price')
  2. const { Provider, Consumer} = PriceContext;
  3. export default { Provider, Consumer }
      • 2.然后将Provider,Consumer解构并导出
      • 3.使用provider包裹父组件并且传递数据
  1. // 父组件
  2. <Provider value={100}>
  3. </Provider>

4.在后代组件内使用Consumer接收数据

  1. // 后代组件
  2. <Consumer>
  3. { /*这里是一个函数*/ }
  4. {
  5. price => <div>price:{price}</div>
  6. }
  7. </Consumer>

13、react diff算法?

react diff算法使用三大策略将算法复杂度O(n^3)转化为了O(n)

策略一(tree diff):

react通过updateDepth(层级修改)对Virtual dom树进行分层级控制,在对比过程中,如果发现节点不存在了会完全删除不会对其他地方进行比较,这样只需要对树遍历一次就可以了

策略二(compoent diff):
    • 拥有相同类的两个组件 生成相似的树形结构,
    • 拥有不同类的两个组件 生成不同的树形结构。
      • 分为三种策略:
        • 同一类型的两个组件,按原策略(层级比较)继续比较Virtual DOM树即可。
        • 同一类型的两个组件,组件A变化为组件B时,可能Virtual DOM没有任何变化,如果知道这点(变换的过程中,Virtual DOM没有改变),可节省大量计算时间,所以 用户 可以通过 shouldComponentUpdate() 来判断是否需要 计算。
        • 不同类型的组件,将一个(将被改变的)组件判断为dirty component(脏组件),从而替换 整个组件的所有节点。
策略三(element diff):

对于同一层级的一组子节点,通过唯一id区分

当节点处于同一层级时,diff提供三种节点操作:删除、插入、移动。

注意:

尽量减少类似将最后一个节点移动到列表首部的操作,当节点数量过大或更新操作过于频繁时,会影响React的渲染性能

14、高阶组件?

定义:

在React中,高阶组件即接受一个或多个组件作为参数并且返回一个组件,本质也就是一个函数,并不是一个组件

作用:
        1. 代码复用:通过将一些通用的逻辑封装在高阶组件中,可以在多个组件之间共享和复用这些逻辑代码,减少重复编写代码的工作量。
        2. 组件增强:高阶组件可以对传入的组件进行功能增强,比如添加额外的props、处理数据逻辑、封装组件的生命周期方法等。
        3. 条件渲染:高阶组件可以根据特定条件来决定是否渲染包裹的组件,实现条件渲染的功能
        1. 性能优化:高阶组件可以通过对组件的渲染过程进行优化,比如缓存组件的渲染结果、减少不必要的渲染等,提升应用的性能
实现:
  1. import React, { Component } from 'react';
  2. export default (WrappedComponent) => {
  3. return class EnhancedComponent extends Component {
  4. // do something
  5. render() {
  6. return <WrappedComponent />;
  7. }
  8. }
  9. }
使用场景:
封装登录鉴权验证:
  1. // withauth.js
  2. import { Navigate } from "react-router-dom";
  3. function AuthComponent(props) {
  4. const children = props.children;
  5. const token = localStorage.getItem("token"); // 假设token保存在localStorage中
  6. if (token) {
  7. return <>{children}</>;
  8. } else {
  9. return <Navigate to="/login" ></Navigate>;
  10. }
  11. }
  12. export default AuthComponent;
  13. // app.js
  14. function App() {
  15. return (
  16. <div className="App">
  17. <div className="app-content">
  18. <WithAuth>
  19. <Outlet></Outlet>
  20. </WithAuth>
  21. </div>
  22. </div>
  23. )
  24. }
性能监控:

记录每次渲染时间

  1. function withTiming(Comp) {
  2. return class extends Comp {
  3. constructor(props) {
  4. super(props);
  5. this.start = Date.now();
  6. this.end = 0;
  7. }
  8. componentDidMount() {
  9. super.componentDidMount && super.componentDidMount();
  10. this.end = Date.now();
  11. console.log(`${WrappedComponent.name} 组件渲染时间为 ${this.end - this.start} ms`);
  12. }
  13. render() {
  14. return super.render();
  15. }
  16. };
  17. }

15、redux的原理?

为什么要使用redux?

在React中,数据在组件中是单向流动的,数据从一个方向父组件流向子组件(通过props),所以,两个非父子组件之间通信就相对麻烦,redux的出现就是为了解决state里面的数据问题

定义:

Redux是将整个应用状态存储到一个地方上称为store,里面保存着一个状态树store tree,组件可以派发(dispatch)行为(action)给store,而不是直接通知其他组件,组件内部通过订阅store中的状态state来刷新自己的视图

redux三大原则:
    • 唯一数据源

整个应用的state都被存储到一个状态树里面,并且这个状态树,只存在于唯一的store中

    • 保持只读状态

state是只读的,唯一改变state的方法就是触发action,action是一个用于描述以发生时间的普通对象

    • 数据改变只能通过纯函数来执行

使用纯函数来执行修改,为了描述action如何改变state的,你需要编写reducers

redux工作流程:

中间件:

实现:
  1. let createStore = (reducer) => {
  2. let state;
  3. //获取状态对象
  4. //存放所有的监听函数
  5. let listeners = [];
  6. let getState = () => state;
  7. //提供一个方法供外部调用派发action
  8. let dispath = (action) => {
  9. //调用管理员reducer得到新的state
  10. state = reducer(state, action);
  11. //执行所有的监听函数
  12. listeners.forEach((l) => l())
  13. }
  14. //订阅状态变化事件,当状态改变发生之后执行监听函数
  15. let subscribe = (listener) => {
  16. listeners.push(listener);
  17. }
  18. dispath();
  19. return {
  20. getState,
  21. dispath,
  22. subscribe
  23. }
  24. }
  25. let combineReducers=(renducers)=>{
  26. //传入一个renducers管理组,返回的是一个renducer
  27. return function(state={},action={}){
  28. let newState={};
  29. for(var attr in renducers){
  30. newState[attr]=renducers[attr](state[attr],action)
  31. }
  32. return newState;
  33. }
  34. }
  35. export {createStore,combineReducers};
使用:
  1. // 1、首先下载@reduxjs/toolkit 和 react-redux;
  2. // 创建一个store目录,在当前index.jsx内进行配置;
  3. import { configureStore } from "@reduxjs/toolkit";
  4. import CounterSlice from "./counterSlice"; //引入counterSlice文件夹
  5. // 合并切片
  6. const store = configureStore({
  7. // 合并多个slice切片
  8. reducer: {
  9. counter: CounterSlice, // 这里的counter就是reducer的名字
  10. ...
  11. },
  12. });
  13. export default store;
  14. //2、 counterSlice/index.jsx
  15. // 创建切片
  16. import { createSlice } from "@reduxjs/toolkit";
  17. export const counterSlice = createSlice({
  18. name: "counter", //切片名称
  19. initialState: { value: 0 }, //初始状态
  20. reducers: {
  21. //reducer函数
  22. increment: (state) => {
  23. state.value += 1; //状态增加
  24. },
  25. decrement: (state) => {
  26. state.value -= 1; //状态减少
  27. },
  28. },
  29. });
  30. //导出action
  31. export const { increment, decrement } = counterSlice.actions;
  32. export default counterSlice.reducer; //导出reducer
  33. // 3、根目录下 //main.jsx;
  34. import store from "./store"; //引入store
  35. import { Provider } from "react-redux"; //通过react-redux引入Provider
  36. // 使用Provider包裹最外层,并且挂载store实例;
  37. ReactDOM.createRoot(document.getElementById("root")).render(
  38. <Provider store={store}>
  39. <RouterProvider router={router}>
  40. <App />
  41. </RouterProvider>
  42. </Provider>
  43. );
  44. // 4、组件内使用 -- list.jsx
  45. /* useDispatch用于派发事件,useSelector用于获取数据*/
  46. import { useDispatch, useSelector } from "react-redux";
  47. /* increment,decrement 用于修改redux状态的事件 */
  48. import { increment, decrement } from "../../store/counterSlice/index.jsx";
  49. // 实例化useSelector方法并且获取store中counter切片的value
  50. const { value } = useSelector((store) => store.counter);
  51. // 实例化dispatch方法
  52. let dispatch = useDispatch();
  53. // 最后操作redux
  54. <Button type="primary" size="small" onClick={() => dispatch(increment())}>
  55. +
  56. </Button>
  57. {value}
  58. <Button type="warning" size="small" onClick={() => dispatch(decrement())}>
  59. -
  60. </Button>

16.、react hooks的理解?

react中hooks主要用来处理副作用和复杂的逻辑

useState:

用于实现state和setState;

在函数组件内本身没有state,函数组件是一个纯函数,执行完即销毁,无法储存state

  1. //count 为访问的数据,setCount 用来修改count的数据;
  2. const [count, setCount] = useState(0) // 传入一个初始值
useEffect

在函数组件内是没有生命周期函数的,执行完则销毁,自己无法生成生命周期;

默认情况纯函数输入参数返回结果无副作用,在函数之外定义全局属性、定时器等等都会产生副作用;

模拟生命周期

componentDidMount ;useEffect依赖[],只在初始化完成时执行一次,后续不会执行;

componentDidUpdate ; useEffect依赖[a,b]或者useEffect(fn)没有写第二个参数,当依赖数据发生变化会重新执行内部函数,不传递任何参数将会一直执行;

componentWillUnmount ; useEffect返回一个函数,return()=>{ 清除定时器以及删除时间等等; }

useMemo

在react中默认父组件变化时,会更新所有子组件;

使用useMemo会缓存对象,避免子组件重复渲染

  1. import React, { useState, memo, useMemo } from 'react'
  2. // 子组件
  3. // function Child({ userInfo }) {
  4. // console.log('Child render...', userInfo)
  5. // return <div>
  6. // <p>This is Child {userInfo.name} {userInfo.age}</p>
  7. // </div>
  8. // }
  9. // 类似 class PureComponent ,对 props 进行浅层比较
  10. const Child = memo(({ userInfo }) => {
  11. console.log('Child render...', userInfo)
  12. return <div>
  13. <p>This is Child {userInfo.name} {userInfo.age}</p>
  14. </div>
  15. })
  16. // 父组件
  17. function App() {
  18. console.log('Parent render...')
  19. const [count, setCount] = useState(0)
  20. const [name, setName] = useState('test')
  21. // const userInfo = { name, age: 20 }
  22. // 用 useMemo 缓存数据,有依赖
  23. // useMemo包裹后返回的对象是同一个,没有创建新的对象地址,不会触发子组件的重新渲染
  24. const userInfo = useMemo(() => {
  25. return { name, age: 21 }
  26. }, [name])
  27. return <div>
  28. <p>
  29. count is {count}
  30. <button onClick={() => setCount(count + 1)}>click</button>
  31. </p>
  32. <Child userInfo={userInfo}></Child>
  33. </div>
  34. }
  35. export default App
useCallback

用于缓存函数,避免子组件频繁更新

useCallback需要配合React.memo使用才生效

  1. import React, { useState, memo, useMemo, useCallback } from 'react'
  2. // 子组件,memo 相当于 PureComponent
  3. const Child = memo(({ userInfo, onChange }) => {
  4. console.log('Child render...', userInfo)
  5. return <div>
  6. <p>This is Child {userInfo.name} {userInfo.age}</p>
  7. <input onChange={onChange}></input>
  8. </div>
  9. })
  10. // 父组件
  11. function App() {
  12. console.log('Parent render...')
  13. const [count, setCount] = useState(0)
  14. const [name, setName] = useState('test')
  15. // 用 useMemo 缓存数据
  16. const userInfo = useMemo(() => {
  17. return { name, age: 21 }
  18. }, [name])
  19. // function onChange(e) {
  20. // console.log(e.target.value)
  21. // }
  22. // 用 useCallback 缓存函数,避免在组件多次渲染中多次创建函数导致引用地址一致
  23. const onChange = useCallback(e => {
  24. console.log(e.target.value)
  25. }, [])
  26. return <div>
  27. <p>
  28. count is {count}
  29. <button onClick={() => setCount(count + 1)}>click</button>
  30. </p>
  31. <Child userInfo={userInfo} onChange={onChange}></Child>
  32. </div>
  33. }
  34. export default App
useRef

用于获取dom节点,以及逻辑处理

  1. import React, { useRef, useEffect } from 'react'
  2. function UseRef() {
  3. const btnRef = useRef(null) // 初始值
  4. // const numRef = useRef(0)
  5. // numRef.current
  6. useEffect(() => {
  7. console.log(btnRef.current) // DOM 节点
  8. }, [])
  9. return <div>
  10. <button ref={btnRef}>click</button>
  11. </div>
  12. }
  13. export default UseRef
useContext

用于处理上下文传递数据

  1. import React, { useContext } from 'react'
  2. // 主题颜色
  3. const themes = {
  4. light: {
  5. foreground: '#000',
  6. background: '#eee'
  7. },
  8. dark: {
  9. foreground: '#fff',
  10. background: '#222'
  11. }
  12. }
  13. // 创建 Context
  14. const ThemeContext = React.createContext(themes.light) // 初始值
  15. function ThemeButton() {
  16. // 在后代组件内使用useContext来接收App组件传递的数据;
  17. const theme = useContext(ThemeContext)
  18. // 展示数据
  19. return <button style={{ background: theme.background, color: theme.foreground }}>
  20. hello world
  21. </button>
  22. }
  23. function Toolbar() {
  24. return <div>
  25. <ThemeButton></ThemeButton>
  26. </div>
  27. }
  28. function App() {
  29. // 在父组件内使用Provider来向所有子组件传递数据
  30. return <ThemeContext.Provider value={themes.dark}>
  31. <Toolbar></Toolbar>
  32. </ThemeContext.Provider>
  33. }
  34. export default App

自定义hooks:

注意事项:

推荐阅读
相关标签