乐趣区

关于react.js:面试官最喜欢问的几个react相关问题

除了在构造函数中绑定 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. 类定义更为简单
  3. 不同的生命周期会使逻辑变得扩散且凌乱,不易保护和治理;
  • 时刻须要关注 this 的指向问题;
  • 代码复用代价高,高阶组件的应用常常会使整个组件树变得臃肿;
  • 状态与 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.flag
const setFlag = (bool) => {
    this.setState({flag: bool,})
}
  1. 生命周期钩子 (useEffect):

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

useEffect(callback,)承受两个参数

  • callback: 钩子回调函数;
  • source: 设置触发条件,仅当 source 产生扭转时才会触发;
  • useEffect 钩子在没有传入参数时,默认在每次 render 时都会优先调用上次保留的回调中返回的函数,后再从新调用回调;
useEffect(() => {
    // 组件挂载后执行事件绑定
    console.log('on')
    addEventListener()

    // 组件 update 时会执行事件解绑
    return () => {console.log('off')
        removeEventListener()}
}, );


// 每次 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. 其它内置钩子:
  2. useContext: 获取 context 对象
  • useReducer: 相似于 Redux 思维的实现,但其并不足以代替 Redux,能够了解成一个组件外部的 redux:

    • 并不是长久化存储,会随着组件被销毁而销毁;
    • 属于组件外部,各个组件是互相隔离的,单纯用它并无奈共享数据;
    • 配合 useContext` 的全局性,能够实现一个轻量级的 Redux;(easy-peasy)
  • useCallback: 缓存回调函数,防止传入的回调每次都是新的函数实例而导致依赖组件从新渲染,具备性能优化的成果;
  • useMemo: 用于缓存传入的 props,防止依赖的组件每次都从新渲染;
  • useRef: 获取组件的实在节点;
  • useLayoutEffect

    • DOM 更新同步钩子。用法与 useEffect 相似,只是区别于执行工夫点的不同
    • useEffect 属于异步执行,并不会期待 DOM 真正渲染后执行,而 useLayoutEffect 则会真正渲染后才触发;
    • 能够获取更新后的 state;
  • 自定义钩子(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): 返回出一个组件,它基于被包裹组件进行 性能加强;
  • 默认参数: 能够为组件包裹一层默认参数;
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 进行来辨别
  2. 如果没有 id 来进行辨别,一旦有插入动作,会导致插入地位之后的列表全副从新渲染
  3. 这也是为什么渲染列表时为什么要应用惟一的 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 倡议应用约束性组件。次要起因是,约東性组件反对即时字段验证,容许有条件地禁用 / 启用按钮,强制输出格局等。

退出移动版