React—生命周期、条件渲染、列表&key

生命周期

1、组件从创建到死亡会经历一些特定的阶段

2、React组件中包含了一系列钩子函数(生命周期回调函数),并且会在特定的时刻调用

3、我们在定义组件时,可以在一些特定的生命周期的回调函数中做一些特定的工作

在这里插入图片描述

挂载阶段:

当组件实例被创建并插入DOM中时,其生命周期调用顺序如下:

  • constructor()
  • static getDerivedStateFromProps()
  • render()
  • componentDidMount()

更新阶段:

当组件中的props或者state发生变化时就会触发更新。组件更新的生命周期调用顺序如下:

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

卸载:

  • componentWillUnmount()
//创建组件
class App extends React.Component {
    //构造器,通常适用于以下两种情况,如果不需要以下两种情况可以不用为组件实现该构造函数
    //通过给this.state赋值对象来初始化内部state
    //为事件处理函数绑定实例
    constructor(props) {
        console.log('Count---constructor');
        super(props)
        //初始化状态
        this.state = { count: 0 }
    }

    //加1按钮的回调
    add = () => {
        //获取原状态
        const { count } = this.state
        //更新状态
        this.setState({ count: count + 1 })
    }

    //卸载组件按钮的回调
    death = () => {
        ReactDOM.unmountComponentAtNode(document.getElementById('root'))
    }

    //强制更新按钮的回调
    force = () => {
        this.forceUpdate()
    }

    //若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
    static getDerivedStateFromProps(props, state) {
        console.log('getDerivedStateFromProps', props, state);
        // 若返回的是null则不会更新任何内容
        return null
    }

    //组件挂载完毕的钩子
    componentDidMount() {
        console.log('Count---componentDidMount');
    }

    //控制组件更新的“阀门”
    shouldComponentUpdate(nextProps, nextState) {
        console.log('Count---shouldComponentUpdate', nextProps, nextState);
        // 若返回值为false则不会调用componentDidUpdate()
        return true
    }

    //组件更新完毕的钩子
    componentDidUpdate(preProps, preState, snapshotValue) {
        console.log('Count---componentDidUpdate', preProps, preState, snapshotValue);
    }

    //在更新之前获取快照
    getSnapshotBeforeUpdate() {
        console.log('getSnapshotBeforeUpdate');
        // 该返回值会传递给componentDidUpdate()中的第三个参数
        return 'nihao'
    }

    //组件将要卸载的钩子
    componentWillUnmount() {
        console.log('Count---componentWillUnmount');
    }

    render() {
        console.log('Count---render');
        const { count } = this.state
        return (
            <div>
                <h2>当前求和为:{count}</h2>
                <button onClick={this.add}>点我+1</button>
                <button onClick={this.death}>卸载组件</button>
                <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
            </div>
        )
    }
}
复制代码

页面第一次挂载:
在这里插入图片描述

点击+1更新state来更新组件:
在这里插入图片描述

强制更新:
在这里插入图片描述
组件卸载:
在这里插入图片描述

生命周期总结:

重要的钩子:

  • render:初始化渲染或者更新渲染时调用

  • componentDidMount:开启监听,发送Ajax请求

  • componentWillUnmount:做一些收尾工作,如:清理定时器

废弃的钩子:

  • componentWillMount

  • componentWillReceiveProps

  • componentWillUpdate

现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。

条件渲染

在React中,可以使用JavaScript中运算符if或者条件运算符去创建元素来表现当前的状态,然后让React根据他们来更新UI

例如有两个组件,通过isLogin的真假来渲染不同的组件内容

function UserGreeting() {
    return <h1>Welcome back!</h1>;
}

function GuestGreeting() {
    return <h1>Please sign up.</h1>;
}

function App(props) {
    if (props.isLogin) {
        return <UserGreeting />;
    } else {
        return <GuestGreeting />
    }
}
复制代码

与运算符&&

通过{}包裹代码,可以在JSX中写入任何表达式

例如

function App(props) {
    const unreadMessage = props.unreadMessage
    
    return (
        <div>
            <h1>Hello!</h1>
            {unreadMessage.length > 0 &&
                <h1>
                    You have {unreadMessage.length} unread messages.
                </h1>
            }
        </div>
    )
}

const messages = ['React', 'Re: React', 'Re:Re: React']

ReactDOM.render(<App unreadMessage={messages} />, document.getElementById("root"));
复制代码

在JavaScript中,当true&&expression时,将会返回expression,而false&&expression时总会返回false

因此在上述例子中如果前者条件为true,则会渲染右侧的元素,若为false,则会忽略并跳过它

三目运算符

在React中不仅可以使用&&运算符来进行条件渲染,也可以使用三目运算符来完成

例如

function App(props) {
    const isLogin = props.isLogin;

    return (
        <h1>
            The user is <b>{isLogin ? 'currently' : 'not'}</b> login in
        </h1>
    )
}
复制代码

列表&key

我们可以像JavaScript中的一些遍历的方法来渲染列表组件,通过使用{}在JSX中构建一个元素集合

例如

function App() {
    const numbers = [1, 2, 3, 4, 5];

    return (
        <h1>
            {numbers.map((number) => (
                <div>{number}</div>
            ))}
        </h1>
    )
}
复制代码

但是这样写会有一个警告Each child in a list should have a unique "key" prop.,意思是当创建一个元素时,必须包括一个特殊的key属性

即改为:

function App() {
    const numbers = [1, 2, 3, 4, 5];

    return (
        <h1>
            {numbers.map((number) => (
                <div key={number}>{number}</div>
            ))}
        </h1>
    )
}
复制代码

DOM的Diffing算法

当setState()更新状态了之后,会重新创建一个新的虚拟DOM树,这个新的虚拟DOM会去跟之前旧的虚拟DOM树进行比较差异,并且更新有差异的部分再将新的数据渲染到真实的DOM上面。

key的作用

key可以帮React识别出来哪些元素改变了,比如被添加或者删除。因此应当给一个数组的每一个元素赋予一个确定的标识。

同时一个元素的key最好是这个元素在列表中拥有一个独一无二的字符串。通常可以使用数据中的id作为元素的key,当元素没有id的时候,也可以将index作为key,但是这样会引起一些问题的出现。

在进行新虚拟DOM和旧虚拟DOM的diff比较时,会有以下规则:

1、如果新虚拟DOM从旧虚拟DOM中找到了相同的key:

  • 若新虚拟DOM中的内容没有变,则直接使用旧虚拟DOM中的内容和之前的真实DOM来渲染到页面上

  • 若新虚拟DOM中的内容发生了变化,则使用新虚拟DOM中的内容,创建新的真实DOM,然后替换掉之前的真实DOM来渲染到页面上

2、如果新虚拟DOM中没有找到与旧虚拟DOM中相同的key,则会直接使用新虚拟DOM中的内容来创建新的真实DOM,然后渲染到页面上

为什么遍历列表,key最好不要使用index?

当使用index作为key时可能引发的问题:

(1)若对数据进行了逆序添加,逆序删除等破坏顺序的操作的话,会产生没有必要的真实DOM更新

(2)若结构中还包含了输入类的DOM,会产生错误的DOM更新,导致页面有问题

class App extends React.Component {
    state = {
        numbers: [1, 2, 3, 4, 5]
    }

    addItem = () => {
        this.setState({
            numbers: [this.state.numbers.length + 1, ...this.state.numbers]
        })
    }
    render() {
        const { numbers } = this.state;
        return (
            <>
                <h3>
                    {numbers.map((number, index) => (
                    // 使用index值作为key值
                        <div key={index}>
                            {number}:
                            <input type="text" />
                        </div>
                    ))}
                </h3>
                <button onClick={this.addItem}>Add Item</button>
            </>
        )
    }
}
复制代码

若使用index作为key值时,对数据进行了逆序的添加删除,此时页面就会出现以下的错误
在这里插入图片描述
在这里插入图片描述

class App extends React.Component {
    state = {
        numbers: [1, 2, 3, 4, 5]
    }

    addItem = () => {
        this.setState({
            numbers: [this.state.numbers.length + 1, ...this.state.numbers]
        })
    }
    render() {
        const { numbers } = this.state;
        return (
            <>
                <h3>
                    {numbers.map((number) => (
                        // 使用唯一的值作为key值
                        <div key={number}>
                            {number}:
                            <input type="text" />
                        </div>
                    ))}
                </h3>
                <button onClick={this.addItem}>Add Item</button>
            </>
        )
    }
}
复制代码

当使用唯一的值作为key值时,无论是正序还是逆序都不会影响到页面。
在这里插入图片描述
在这里插入图片描述

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享