写点什么

面试官最喜欢问的几个 react 相关问题

作者:beifeng1996
  • 2022-11-07
    浙江
  • 本文字数:10571 字

    阅读完需:约 35 分钟

除了在构造函数中绑定 this,还有其它方式吗

你可以使用属性初始值设定项(property initializers)来正确绑定回调,create-react-app 也是默认支持的。在回调中你可以使用箭头函数,但问题是每次组件渲染时都会创建一个新的回调。

一般可以用哪些值作为 key

  • 最好使用每一条数据中的唯一标识作为 key,比如:手机号,id 值,身份证号,学号等

  • 也可以用数据的索引值(可能会出现一些问题)

React 性能优化

  • shouldCompoentUpdate

  • pureComponent 自带 shouldCompoentUpdate 的浅比较优化

  • 结合 Immutable.js 达到最优

diff 算法?

  • 把树形结构按照层级分解,只比较同级元素

  • 给列表结构的每个单元添加唯一的 key 属性,方便比较

  • React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)

  • 合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个 事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.

  • 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。


参考:前端react面试题详细解答

refs 的作用是什么,你在什么样的业务场景下使用 refs

  • 操作 DOM,为什么操作 DOM?

  • 场景

  • 图片渲染好后,操作图片宽高。比如做个放大镜功能

setState

在了解 setState 之前,我们先来简单了解下 React 一个包装结构: Transaction:


事务 (Transaction)


是 React 中的一个调用结构,用于包装一个方法,结构为: initialize - perform(method) - close。通过事务,可以统一管理一个方法的开始与结束;处于事务流中,表示进程正在执行一些操作


  • setState: React 中用于修改状态,更新视图。它具有以下特点:


异步与同步: setState 并不是单纯的异步或同步,这其实与调用时的环境相关:


  • 合成事件生命周期钩子 (除 componentDidUpdate) 中,setState 是"异步"的;

  • 原因: 因为在 setState 的实现中,有一个判断: 当更新策略正在事务流的执行中时,该组件更新会被推入 dirtyComponents 队列中等待执行;否则,开始执行 batchedUpdates 队列更新;

  • 在生命周期钩子调用中,更新策略都处于更新之前,组件仍处于事务流中,而 componentDidUpdate 是在更新之后,此时组件已经不在事务流中了,因此则会同步执行;

  • 在合成事件中,React 是基于 事务流完成的事件委托机制 实现,也是处于事务流中;

  • 问题: 无法在 setState 后马上从 this.state 上获取更新后的值。

  • 解决: 如果需要马上同步去获取新值,setState 其实是可以传入第二个参数的。setState(updater, callback),在回调中即可获取最新值;

  • 原生事件 和 setTimeout 中,setState 是同步的,可以马上获取更新后的值;

  • 原因: 原生事件是浏览器本身的实现,与事务流无关,自然是同步;而 setTimeout 是放置于定时器线程中延后执行,此时事务流已结束,因此也是同步;

  • 批量更新 : 在 合成事件 和 生命周期钩子 中,setState 更新队列时,存储的是 合并状态(Object.assign)。因此前面设置的 key 值会被后面所覆盖,最终只会执行一次更新;

  • 函数式 : 由于 Fiber 及 合并 的问题,官方推荐可以传入 函数 的形式。setState(fn),在 fn 中返回新的 state 对象即可,例如 this.setState((state, props) => newState);

  • 使用函数式,可以用于避免 setState 的批量更新的逻辑,传入的函数将会被 顺序调用;


注意事项:


  • setState 合并,在 合成事件 和 生命周期钩子 中多次连续调用会被优化为一次;

  • 当组件已被销毁,如果再次调用 setState,React 会报错警告,通常有两种解决办法

  • 将数据挂载到外部,通过 props 传入,如放到 Redux 或 父级中;

  • 在组件内部维护一个状态量 (isUnmounted),componentWillUnmount 中标记为 true,在 setState 前进行判断;

新版生命周期

在新版本中,React 官方对生命周期有了新的 变动建议:


  • 使用getDerivedStateFromProps替换componentWillMount;

  • 使用getSnapshotBeforeUpdate替换componentWillUpdate;

  • 避免使用componentWillReceiveProps


其实该变动的原因,正是由于上述提到的 Fiber。首先,从上面我们知道 React 可以分成 reconciliationcommit两个阶段,对应的生命周期如下:


reconciliation


  • componentWillMount

  • componentWillReceiveProps

  • shouldComponentUpdate

  • componentWillUpdate


commit


  • componentDidMount

  • componentDidUpdate

  • componentWillUnmount


Fiber 中,reconciliation 阶段进行了任务分割,涉及到 暂停 和 重启,因此可能会导致 reconciliation 中的生命周期函数在一次更新渲染循环中被 多次调用 的情况,产生一些意外错误


新版的建议生命周期如下:


class Component extends React.Component {  // 替换 `componentWillReceiveProps` ,  // 初始化和 update 时被调用  // 静态函数,无法使用 this  static getDerivedStateFromProps(nextProps, prevState) {}
// 判断是否需要更新组件 // 可以用于组件性能优化 shouldComponentUpdate(nextProps, nextState) {}
// 组件被挂载后触发 componentDidMount() {}
// 替换 componentWillUpdate // 可以在更新之前获取最新 dom 数据 getSnapshotBeforeUpdate() {}
// 组件更新后调用 componentDidUpdate() {}
// 组件即将销毁 componentWillUnmount() {}
// 组件已销毁 componentDidUnMount() {}}
复制代码


使用建议:


  • constructor初始化 state

  • componentDidMount中进行事件监听,并在componentWillUnmount中解绑事件;

  • componentDidMount中进行数据的请求,而不是在componentWillMount

  • 需要根据 props 更新 state 时,使用getDerivedStateFromProps(nextProps, prevState)

  • 旧 props 需要自己存储,以便比较;


public static getDerivedStateFromProps(nextProps, prevState) {    // 当新 props 中的 data 发生变化时,同步更新到 state 上    if (nextProps.data !== prevState.data) {        return {            data: nextProps.data        }    } else {        return null1    }}
复制代码


可以在 componentDidUpdate 监听 props 或者 state 的变化,例如:


componentDidUpdate(prevProps) {    // 当 id 发生变化时,重新获取数据    if (this.props.id !== prevProps.id) {        this.fetchData(this.props.id);    }}
复制代码


  • 在 componentDidUpdate 使用 setState 时,必须加条件,否则将进入死循环;

  • getSnapshotBeforeUpdate(prevProps, prevState)可以在更新之前获取最新的渲染数据,它的调用是在 render 之后, update 之前;

  • shouldComponentUpdate: 默认每次调用 setState,一定会最终走到 diff 阶段,但可以通过 shouldComponentUpdate 的生命钩子返回 false 来直接阻止后面的逻辑执行,通常是用于做条件渲染,优化渲染的性能。

调用 setState 之后发生了什么

在代码中调用 setState 函数之后,React 会将传入的参数与之前的状态进行合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在 React 得到元素树之后,React 会计算出新的树和老的树之间的差异,然后根据差异对界面进行最小化重新渲染。通过 diff 算法,React 能够精确制导哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。


  • 在 setState 的时候,React 会为当前节点创建一个 updateQueue 的更新列队。

  • 然后会触发 reconciliation 过程,在这个过程中,会使用名为 Fiber 的调度算法,开始生成新的 Fiber 树, Fiber 算法的最大特点是可以做到异步可中断的执行。

  • 然后 React Scheduler 会根据优先级高低,先执行优先级高的节点,具体是执行 doWork 方法。

  • 在 doWork 方法中,React 会执行一遍 updateQueue 中的方法,以获得新的节点。然后对比新旧节点,为老节点打上 更新、插入、替换 等 Tag。

  • 当前节点 doWork 完成后,会执行 performUnitOfWork 方法获得新节点,然后再重复上面的过程。

  • 当所有节点都 doWork 完成后,会触发 commitRoot 方法,React 进入 commit 阶段。

  • 在 commit 阶段中,React 会根据前面为各个节点打的 Tag,一次性更新整个 dom 元素

shouldComponentUpdate 有什么用?为什么它很重要?

组件状态数据或者属性数据发生更新的时候,组件会进入存在期,视图会渲染更新。在生命周期方法 should ComponentUpdate 中,允许选择退出某些组件(和它们的子组件)的和解过程。和解的最终目标是根据新的状态,以最有效的方式更新用户界面。如果我们知道用户界面的某一部分不会改变,那么没有理由让 React 弄清楚它是否应该更新渲染。通过在 shouldComponentUpdate 方法中返回 false, React 将让当前组件及其所有子组件保持与当前组件状态相同。

diff 算法?


  • 把树形结构按照层级分解,只比较同级元素。

  • 给列表结构的每个单元添加唯一的key属性,方便比较。

  • React 只会匹配相同 classcomponent(这里面的class指的是组件的名字)

  • 合并操作,调用 componentsetState 方法的时候, React 将其标记为 - dirty.到每一个事件循环结束, React 检查所有标记 dirtycomponent重新绘制.

  • 选择性子树渲染。开发人员可以重写shouldComponentUpdate提高diff的性能

react 性能优化是哪个周期函数

shouldComponentUpdate 这个方法用来判断是否需要调用 render 方法重新描绘 dom。因为 dom 的描绘非常消耗性能,如果我们能在shouldComponentUpdate方法中能够写出更优化的dom diff算法,可以极大的提高性能

说说 React 组件开发中关于作用域的常见问题。

在 EMAScript5 语法规范中,关于作用域的常见问题如下。(1)在 map 等方法的回调函数中,要绑定作用域 this(通过 bind 方法)。(2)父组件传递给子组件方法的作用域是父组件实例化对象,无法改变。(3)组件事件回调函数方法的作用域是组件实例化对象(绑定父组件提供的方法就是父组件实例化对象),无法改变。在 EMAScript6 语法规范中,关于作用域的常见问题如下。(1)当使用箭头函数作为 map 等方法的回调函数时,箭头函数的作用域是当前组件的实例化对象(即箭头函数的作用域是定义时的作用域),无须绑定作用域。(2)事件回调函数要绑定组件作用域。(3)父组件传递方法要绑定父组件作用域。总之,在 EMAScript6 语法规范中,组件方法的作用域是可以改变的。

react 的渲染过程中,兄弟节点之间是怎么处理的?也就是 key 值不一样的时候

通常我们输出节点的时候都是 map 一个数组然后返回一个ReactNode,为了方便react内部进行优化,我们必须给每一个reactNode添加key,这个key prop在设计值处不是给开发者用的,而是给 react 用的,大概的作用就是给每一个reactNode添加一个身份标识,方便 react 进行识别,在重渲染过程中,如果 key 一样,若组件属性有所变化,则react只更新组件对应的属性;没有变化则不更新,如果 key 不一样,则 react 先销毁该组件,然后重新创建该组件

createElement 与 cloneElement 的区别是什么

createElement 函数是 JSX 编译之后使用的创建 React Element 的函数,而 cloneElement 则是用于复制某个元素并传入新的 Props

在 ReactNative 中,如何解决 8081 端口号被占用而提示无法访问的问题?

在运行 react-native start 时添加参数 port 8082;在 package.json 中修改“scripts”中的参数,添加端口号;修改项目下的 node_modules \react-native\local- cli\server\server.js 文件配置中的 default 端口值。

react hooks,它带来了那些便利

  • 代码逻辑聚合,逻辑复用

  • HOC 嵌套地狱

  • 代替 class


React 中通常使用 类定义 或者 函数定义 创建组件:


在类定义中,我们可以使用到许多 React 特性,例如 state、 各种组件生命周期钩子等,但是在函数定义中,我们却无能为力,因此 React 16.8 版本推出了一个新功能 (React Hooks),通过它,可以更好的在函数定义组件中使用 React 特性。


好处:


  1. 跨组件复用: 其实 render props / HOC 也是为了复用,相比于它们,Hooks 作为官方的底层 API,最为轻量,而且改造成本小,不会影响原来的组件层次结构和传说中的嵌套地狱;

  2. 类定义更为复杂


  • 不同的生命周期会使逻辑变得分散且混乱,不易维护和管理;

  • 时刻需要关注 this 的指向问题;

  • 代码复用代价高,高阶组件的使用经常会使整个组件树变得臃肿;


  1. 状态与 UI 隔离: 正是由于 Hooks 的特性,状态逻辑会变成更小的粒度,并且极容易被抽象成一个自定义 Hooks,组件中的状态和 UI 变得更为清晰和隔离。


注意:


  • 避免在 循环/条件判断/嵌套函数 中调用 hooks,保证调用顺序的稳定;

  • 只有 函数定义组件 和 hooks 可以调用 hooks,避免在 类组件 或者 普通函数 中调用;

  • 不能在 useEffect 中使用 useState,React 会报错提示;

  • 类组件不会被替换或废弃,不需要强制改造类组件,两种方式能并存;


重要钩子


  1. 状态钩子 (useState): 用于定义组件的 State,其到类定义中 this.state 的功能;


// useState 只接受一个参数: 初始状态// 返回的是组件名和更改该组件对应的函数const [flag, setFlag] = useState(true);// 修改状态setFlag(false)
// 上面的代码映射到类定义中:this.state = { flag: true }const flag = this.state.flagconst setFlag = (bool) => { this.setState({ flag: bool, })}
复制代码


  1. 生命周期钩子 (useEffect):


类定义中有许多生命周期函数,而在 React Hooks 中也提供了一个相应的函数 (useEffect),这里可以看做 componentDidMount、componentDidUpdate 和 componentWillUnmount 的结合。


useEffect(callback, [source])接受两个参数


  • callback: 钩子回调函数;

  • source: 设置触发条件,仅当 source 发生改变时才会触发;

  • useEffect 钩子在没有传入[source]参数时,默认在每次 render 时都会优先调用上次保存的回调中返回的函数,后再重新调用回调;


useEffect(() => {    // 组件挂载后执行事件绑定    console.log('on')    addEventListener()
// 组件 update 时会执行事件解绑 return () => { console.log('off') removeEventListener() }}, [source]);

// 每次 source 发生改变时,执行结果(以类定义的生命周期,便于大家理解):// --- DidMount ---// 'on'// --- DidUpdate ---// 'off'// 'on'// --- DidUpdate ---// 'off'// 'on'// --- WillUnmount --- // 'off'
复制代码


通过第二个参数,我们便可模拟出几个常用的生命周期:


  • componentDidMount: 传入[]时,就只会在初始化时调用一次


const useMount = (fn) => useEffect(fn, [])
复制代码


  • componentWillUnmount: 传入[],回调中的返回的函数也只会被最终执行一次


const useUnmount = (fn) => useEffect(() => fn, [])
复制代码


  • mounted: 可以使用 useState 封装成一个高度可复用的 mounted 状态;


const useMounted = () => {    const [mounted, setMounted] = useState(false);    useEffect(() => {        !mounted && setMounted(true);        return () => setMounted(false);    }, []);    return mounted;}
复制代码


  • componentDidUpdate: useEffect 每次均会执行,其实就是排除了 DidMount 后即可;


const mounted = useMounted() useEffect(() => {    mounted && fn()})
复制代码


  1. 其它内置钩子:


  • useContext: 获取 context 对象

  • useReducer: 类似于 Redux 思想的实现,但其并不足以替代 Redux,可以理解成一个组件内部的 redux:

  • 并不是持久化存储,会随着组件被销毁而销毁;

  • 属于组件内部,各个组件是相互隔离的,单纯用它并无法共享数据;

  • 配合 useContext`的全局性,可以完成一个轻量级的 Redux;(easy-peasy)

  • useCallback: 缓存回调函数,避免传入的回调每次都是新的函数实例而导致依赖组件重新渲染,具有性能优化的效果;

  • useMemo: 用于缓存传入的 props,避免依赖的组件每次都重新渲染;

  • useRef: 获取组件的真实节点;

  • useLayoutEffect

  • DOM 更新同步钩子。用法与 useEffect 类似,只是区别于执行时间点的不同

  • useEffect 属于异步执行,并不会等待 DOM 真正渲染后执行,而 useLayoutEffect 则会真正渲染后才触发;

  • 可以获取更新后的 state;


  1. 自定义钩子(useXxxxx): 基于 Hooks 可以引用其它 Hooks 这个特性,我们可以编写自定义钩子,如上面的 useMounted。又例如,我们需要每个页面自定义标题:


function useTitle(title) {  useEffect(    () => {      document.title = title;    });}
// 使用:function Home() { const title = '我是首页' useTitle(title)
return ( <div>{title}</div> )}
复制代码

HOC(高阶组件)

HOC(Higher Order Componennt) 是在 React 机制下社区形成的一种组件模式,在很多第三方开源库中表现强大。


简述:


  • 高阶组件不是组件,是 增强函数,可以输入一个元组件,返回出一个新的增强组件;

  • 高阶组件的主要作用是 代码复用,操作 状态和参数;


用法:


  • 属性代理 (Props Proxy): 返回出一个组件,它基于被包裹组件进行 功能增强;


  1. 默认参数: 可以为组件包裹一层默认参数;


function proxyHoc(Comp) {    return class extends React.Component {        render() {            const newProps = {                name: 'tayde',                age: 1,            }            return <Comp {...this.props} {...newProps} />        }    }}
复制代码


  1. 提取状态: 可以通过 props 将被包裹组件中的 state 依赖外层,例如用于转换受控组件:


function withOnChange(Comp) {    return class extends React.Component {        constructor(props) {            super(props)            this.state = {                name: '',            }        }        onChangeName = () => {            this.setState({                name: 'dongdong',            })        }        render() {            const newProps = {                value: this.state.name,                onChange: this.onChangeName,            }            return <Comp {...this.props} {...newProps} />        }    }}
复制代码


使用姿势如下,这样就能非常快速的将一个 Input 组件转化成受控组件。


const NameInput = props => (<input name="name" {...props} />)export default withOnChange(NameInput)
复制代码


包裹组件: 可以为被包裹元素进行一层包装,


function withMask(Comp) {  return class extends React.Component {      render() {          return (              <div>                  <Comp {...this.props} />                    <div style={{                      width: '100%',                      height: '100%',                      backgroundColor: 'rgba(0, 0, 0, .6)',                  }}               </div>          )      }  }}
复制代码


反向继承 (Inheritance Inversion): 返回出一个组件,继承于被包裹组件,常用于以下操作


function IIHoc(Comp) {    return class extends Comp {        render() {            return super.render();        }    };}
复制代码


渲染劫持 (Render Highjacking)


条件渲染: 根据条件,渲染不同的组件


function withLoading(Comp) {    return class extends Comp {        render() {            if(this.props.isLoading) {                return <Loading />            } else {                return super.render()            }        }    };}
复制代码


可以直接修改被包裹组件渲染出的 React 元素树


操作状态 (Operate State) : 可以直接通过 this.state 获取到被包裹组件的状态,并进行操作。但这样的操作容易使 state 变得难以追踪,不易维护,谨慎使用。


应用场景:


权限控制,通过抽象逻辑,统一对页面进行权限判断,按不同的条件进行页面渲染:


function withAdminAuth(WrappedComponent) {    return class extends React.Component {        constructor(props){            super(props)            this.state = {                isAdmin: false,            }        }         async componentWillMount() {            const currentRole = await getCurrentUserRole();            this.setState({                isAdmin: currentRole === 'Admin',            });        }        render() {            if (this.state.isAdmin) {                return <Comp {...this.props} />;            } else {                return (<div>您没有权限查看该页面,请联系管理员!</div>);            }        }    };}
复制代码


性能监控 ,包裹组件的生命周期,进行统一埋点:


function withTiming(Comp) {    return class extends Comp {        constructor(props) {            super(props);            this.start = Date.now();            this.end = 0;        }        componentDidMount() {            super.componentDidMount && super.componentDidMount();            this.end = Date.now();            console.log(`${WrappedComponent.name} 组件渲染时间为 ${this.end - this.start} ms`);        }        render() {            return super.render();        }    };}
复制代码


代码复用,可以将重复的逻辑进行抽象。


使用注意:


  • 纯函数: 增强函数应为纯函数,避免侵入修改元组件;

  • 避免用法污染: 理想状态下,应透传元组件的无关参数与事件,尽量保证用法不变;

  • 命名空间: 为 HOC 增加特异性的组件名称,这样能便于开发调试和查找问题;

  • 引用传递 : 如果需要传递元组件的 refs 引用,可以使用 React.forwardRef;

  • 静态方法 : 元组件上的静态方法并无法被自动传出,会导致业务层无法调用;解决:

  • 函数导出

  • 静态方法赋值

  • 重新渲染: 由于增强函数每次调用是返回一个新组件,因此如果在 Render 中使用增强函数,就会导致每次都重新渲染整个 HOC,而且之前的状态会丢失;

React 的虚拟 DOM 和 Diff 算法的内部实现

传统 diff 算法的时间复杂度是 O(n^3),这在前端 render 中是不可接受的。为了降低时间复杂度,react 的 diff 算法做了一些妥协,放弃了最优解,最终将时间复杂度降低到了 O(n)。


那么 react diff 算法做了哪些妥协呢?,参考如下:


  1. tree diff:只对比同一层的 dom 节点,忽略 dom 节点的跨层级移动


如下图,react 只会对相同颜色方框内的 DOM 节点进行比较,即同一个父节点下的所有子节点。当发现节点不存在时,则该节点及其子节点会被完全删除掉,不会用于进一步的比较。


这样只需要对树进行一次遍历,便能完成整个 DOM 树的比较。



这就意味着,如果 dom 节点发生了跨层级移动,react 会删除旧的节点,生成新的节点,而不会复用。


  1. component diff:如果不是同一类型的组件,会删除旧的组件,创建新的组件



  1. element diff:对于同一层级的一组子节点,需要通过唯一 id 进行来区分


  • 如果没有 id 来进行区分,一旦有插入动作,会导致插入位置之后的列表全部重新渲染

  • 这也是为什么渲染列表时为什么要使用唯一的 key。

redux 有什么缺点

  • 一个组件所需要的数据,必须由父组件传过来,而不能像flux中直接从store取。

  • 当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新render,可能会有效率影响,或者需要写复杂的shouldComponentUpdate进行判断。

约束性组件( controlled component)与非约束性组件( uncontrolled  component)有什么区别?

在 React 中,组件负责控制和管理自己的状态。如果将 HTML 中的表单元素( input、 select、 textarea 等)添加到组件中,当用户与表单发生交互时,就涉及表单数据存储问题。根据表单数据的存储位置,将组件分成约東性组件和非约東性组件。约束性组件( controlled component)就是由 React 控制的组件,也就是说,表单元素的数据存储在组件内部的状态中,表单到底呈现什么由组件决定。如下所示, username 没有存储在 DOM 元素内,而是存储在组件的状态中。每次要更新 username 时,就要调用 setState 更新状态;每次要获取 username 的值,就要获取组件状态值。


class App extends Component {  //初始化状态  constructor(props) {    super(props);    this.state = {      username: "有课前端网",    };  }  //查看结果  showResult() {    //获取数据就是获取状态值    console.log(this.state.username);  }  changeUsername(e) {    //原生方法获取    var value = e.target.value;    //更新前,可以进行脏值检测    //更新状态    this.setState({      username: value,    });  }  //渲染组件  render() {    //返回虚拟DOM    return (      <div>        <p>          {/*输入框绑定va1ue*/}          <input type="text" onChange={this.changeUsername.bind(this)} value={this.state.username} />        </p>        <p>          <button onClick={this.showResult.bind(this)}>查看结果</button>        </p>      </div>    );  }}
复制代码


非约束性组件( uncontrolled component)就是指表单元素的数据交由元素自身存储并处理,而不是通过 React 组件。表单如何呈现由表单元素自身决定。如下所示,表单的值并没有存储在组件的状态中,而是存储在表单元素中,当要修改表单数据时,直接输入表单即可。有时也可以获取元素,再手动修改它的值。当要获取表单数据时,要首先获取表单元素,然后通过表单元素获取元素的值。注意:为了方便在组件中获取表单元素,通常为元素设置 ref 属性,在组件内部通过 refs 属性获取对应的 DOM 元素。


class App extends Component {  //查看结果  showResult() {    //获取值    console.log(this.refs.username.value);    //修改值,就是修改元素自身的值    this.refs.username.value = "专业前端学习平台";    //渲染组件    //返回虚拟DOM    return (      <div>        <p>          {/*非约束性组件中,表单元素通过 defaultvalue定义*/}          <input type="text" ref=" username" defaultvalue="有课前端网" />        </p>        <p>          <button onClick={this.showResult.bind(this)}>查看结果</button>        </p>      </div>    );  }}
复制代码


虽然非约東性组件通常更容易实现,可以通过 refs 直接获取 DOM 元素,并获取其值,但是 React 建议使用约束性组件。主要原因是,约東性组件支持即时字段验证,允许有条件地禁用/启用按钮,强制输入格式等。


用户头像

beifeng1996

关注

还未添加个人签名 2022-09-01 加入

还未添加个人简介

评论

发布
暂无评论
面试官最喜欢问的几个react相关问题_React_beifeng1996_InfoQ写作社区