美文网首页
React基础

React基础

作者: Joemoninni | 来源:发表于2020-10-26 15:10 被阅读0次

学习记录

// 尽管this.props和this.state是React本身设置的,且都拥有特殊的含义,但是其实你可以向class中随意添加不参与数据流(比如计时器Id)的额外字段
componentDidMount() {
    this.timeId = setInterval(() => { // 这里把计时器Id(timeId)保存在this之中(this.timeId)
        this.tick()
    }, 1000)
}

// 我们会在componentWillUnmount()生命周期方法中清楚定时器:
componentWillUnmount() {
    clearInterval(this.timeId)
}
 正确使用State
// 1. 不要直接修改 State
/**
    应该使用this.setState()
    构造函数(constructor)是唯一可以给this.state赋值的地方
*/

// 2. State的更新可能是异步的
/**
    因为this.props和this.state可能会异步更新,也就是暂时挂起,先执行后面的任务,所以不要依赖他们的值来更新下一个状态。
    
    // 错误代码
    this.setState({
        counter: this.state.counter + this.props.increment 
    })
    
    要解决这个问题,可以让setState()接收一个函数而不是一个对象,这个函数用上一个state作为第一个参数,将此次更新被应用时的props作为第二个参数
    // 正确代码
    this.setState((state, props) => ({ // 注意: 这里接收的函数返回的是一个对象, 否则报错
        counter: state.counter + props.increment
    }));
*/

// 3. State的更新会被合并
/**
    即在this.setState({})接收的对象中,有写的属性就更新,没写的就不变   
*/
数据是向下流动的
// (父组件)可以选择把它的state或者上一级传过来的props作为props向下传递到它的子组件中, 子组件会在其props中接收父组件传过来的参数,但是子组件无法知道它是来自于父组件的state,还是父组件的props,还是自己手动输入的。

常用的生命周期方法

生命周期图谱https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

image-20201020140657294.png

render()

render()方法是class组件中唯一必须实现的方法。

render()被调用时,他会检查this.propsthis.state的变化并返回以下类型之一:

默认情况下,当组件的stateprops发生变化时,组件将重新渲染。如果render()方法依赖于其他数据,则可以调用forceUpdate()强制让组件重新渲染。

调用forceUpdate()将致使组件调用render()方法,此操作会跳过该组件的shouldComponentUpdate()。但其子组件会触发正常的生命周期方法。

不过通常我们应该避免使用forceUpdate(),尽量在render()中使用this.propsthis.state

  • React元素。通常通过JSX创建。DOM节点 / 自定义组件
  • 数组或者fragments。使得render方法可以返回多个元素,Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点<React.Fragment>子列表分组</React.Fragment>
  • Portals。可以渲染子节点到不同的DOM子树中。
  • 字符串或数值类型。它们在DOM中会被渲染为文本节点
  • 布尔类型或null。什么都不渲染。(主要用于支持返回test && <Child />的模式,其中test为布尔类型)

render()函数应该为纯函数,即在不修改组件state的情况下,每次调用都返回相同的结果,并且他不会直接与浏览器交互。如需与浏览器进行交互,请在componentDidMount或其他生命周期中执行你的操作。

注意:

如果shouldComponendtUpdate()返回false,则不会调用render()

constructor():在组件挂载之前调用

constructor(props)

通常,在React中,constructor构造函数仅用于以下两种情况:

  1. 通过给this.state来初始化内部state
  2. 为事件处理函数绑定实例this.handleClick = this.handleClick.bind(this)

注意:

在为React.Component子类实现构造函数时,应在其他语句之前调用super(props),否则会出现this.props未定义的bug

要避免在constructor构造函数中引入任何副作用和订阅。应该把对应的操作放在componentDidMount

componentDidMount():在组件挂载后(插入DOM树中)立即调用

依赖于DOM节点的初始化应该放在这里。如请求获取数据,此处是实例化请求的好地方。也可以添加订阅,但是记住要在componentWillUnmount()里取消订阅

componentDidUpdate():在组件更新后立即调用。

首次渲染不会执行此方法。可以对比更新前后的props,也可在此处进行网络请求。(如,当props未发生变化时,则不会执行网络请求)

注意:

如果shouldComponentUpdate()返回值为false,则不会调用componentDidUpdate()

componentWillUnmount():在组件卸载及销毁之前调用

在此方法执行必要的清理操作,例如,清除定时器,取消网络请求或清除订阅

事件处理

  1. 阻止默认行为

    在React中不能通过返回false的方式来阻止默认行为(比如a标签的跳转),必须显式地使用e.preventDefault()

  2. 绑定this

    建议使用class field语法,不建议使用箭头函数,使用箭头函数会有性能问题

    handleClick = () => {
        console.log('this is: ' + this)
    }
    
  3. 传递参数

    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> // 箭头函数:事件对象e必须显式地进行传递
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button> // bind: 事件对象e会被隐式地进行传递
    

状态提升

在React应用中,任何可变数据应当只有一个相对应的唯一“数据源”。通常,state都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流,而不是尝试在不同组件间同步state

组合 vs 继承

有点类似于vue中的插槽。

React推荐使用组合而非继承来实现组件间的代码重用

父组件中在子元素标签之间直接写入一些元素,然后在子组件中通过{this.props.children}来接收这些元素并渲染到结果中

// Child.js
function Child(props) {
    return (
        <div>
            {props.children}
            <div className="left">
                {props.left}
            </div>
        </div>
    )
}

// Father.js
function Father() {
    return (
        <Child left={<Custom />}>
            <h1>title</h1>
            <p>content</p>
        </Child>
    )
}

注意:

组合同样适合于class组件

组件可以接收任意的props,包括基本数据类型(比如要给dialog传一个"title"),React元素(上面代码的情况)以及函数(render props就是通过传递一个返回React元素的函数来实现的)

一般都不会用到继承,如果想要在组件间复用非UI的功能,建议将其提取为一个单独的javascript模块,如函数,对象或类。组件可以直接引入(import),而无需通过extend继承它们。

相关文章

网友评论

      本文标题:React基础

      本文链接:https://www.haomeiwen.com/subject/bmbamktx.html