React 问题积累第一天

227 阅读4分钟

问题一:React中有几种函数与事件绑定的方式(提示bind),及其优缺点?

为什么:

(翻译过来就是:在Class不会自动绑定实例) In JavaScript, class methods are not bound by default. Therefore, it’s important that we bind functions to the class instance.

(翻译过来就是:react为了高性能的组件,将所有事件都绑定到了document上,在使用时在反过来寻找组件实例,那么我们反过来没有绑定this实例,我们又怎么访问this.state?) It achieves high performance by automatically using event delegation. In actuality, React doesn’t attach event handlers to the nodes themselves. Instead, a single event listener is attached to the root of the document; when an event is fired, React maps it to the appropriate component element.

怎么做:

方案一:在构造函数中使用bind绑定this
class EX extends React.Component {
    constructor(props) {
        super(props);
        this.handleClick = this.handleButtonClick.bind(this,e);
    }
    handleButtonClick() {
        // doSome
    }
    render() {
        return (<Button onClick={this.handleClick}></Button>)
    }
}
优缺点:也是是用来ES6的bind语法,性能好,但是在很多回调函数中,就比较累赘


方案二:在render的时候使用bind绑定this
class EX extends React.Component {
    constructor(props) {
        super(props);
    }
    handleButtonClick(e) {
        // doSome
    }
    render() {
        return (<Button onClick={this.handleButtonClick.bind(this,e)}></Button>)
    }
}
优缺点:
(这里实用了ES6中bind的语法,bind将函数手动绑定了当前this实例)
Any ES6 class method is a plain JavaScript function; therefore, it inherits
bind() from the Function method. So now when we call onChange() inside JSX,
this will point to our class instance. Easy-peasy.

(但是每次reallocated === 重新分配的时候,每次都render渲染)
However, using this method means that there might be some performance
implications since the function is reallocated on every render. This
performance cost might be not be visible at all in small React apps, but it
could become noticeable in bigger React apps.


方案三:使用匿名箭头函数在 render 中绑定
class EX extends React.Component {
    constructor(props) {
        super(props);
    }
    handleButtonClick() {
        // doSome
    }
    render() {
        return (<Button onClick={() => {this.handleButtonClick(val)}}></Button>)
    }
}
优缺点:
(箭头函数本身的优点就是,本身不具备上下文,就不剧本this,arguments等内容,并且一但箭头函数被创建,它就不会被改变)
By definition, an arrow function expression has a shorter syntax than a
function expression and does not have its own this, arguments, super, or
new.target.
(但是这个方法依然又性能问题,还是在render的时候重新分配渲染)
This methods also has its performance costs, just like binding in the render function method.

方案四:使用箭头函数进行绑定(利用箭头函数绑定this的原理)
class EX extends React.Component {
    constructor(props) {
        super(props);
    }
    handleButtonClick = (e) => {
        // doSome
    }
    render() {
        return (<Button onClick={this.handleButtonClick}></Button>)
    }
}

比较推荐的一个方法,虽然也存在一些性能问题,但是相对方案2,3而言,较好
如果性能问题比较严重,可以使用方案1

思考:各种传参方式(默认参数e和自定义参数id等内容)?

A guide to React onClick event handlers


问题二:React中怎么让一个组件同时支持受控、非受控?

分解问题:什么叫做受控组件?什么叫做非受控组件? 在大多数情况下,我们推荐使用受控组件来处理表单数据。在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。非受控组件is bad?

解决问题:那么怎么让一个组件同时接受受控和非受控呢?1:组件通过prop和construction来获取初始化数据,2:同时组件内部维护state内部数据,3:在input等输入框用户输入值等时候,又同步更新prop外部数据,同时保存两份数据,其实说起来并不可取并且官方不建议。你可能不需要使用派生 state

建议模式:

  1. 完全可控的组件(可控组件,删除state,提升到props中)
  2. 有 key 的非可控组件(通过key值不一样,而重新渲染 + 非可控组件)
  3. memoization减轻 rerender 复杂度

问题三:React中setState为什么有时候是同步的,有时候是异步的?

在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state。所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。

在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。 setState何时同步更新状态


思考:下面2幅图分别输出什么?