资讯专栏INFORMATION COLUMN

React 导读(二)

Doyle / 3114人阅读

摘要:对于最开始关注的是的初始化以及在哪里请求。在进行初始化,推荐在中进行请求。是在组件即将被卸载前一刻的钩子,一般用于取消中订阅的事件等作用,清理一些不要的变量等,避免内存泄漏。第二条的原因额,说好的更新才调,初始化不调用是符合逻辑的。

前言

在上篇文章React 导读(一)中学习到了写第一个 Web 组件,这篇文章将继续之前的目录,开始新的知识点补充:

[x] React 如何编写 Hello World!

[x] React 中三个最基础、最重要的东西

[x] React 中的 JSX

[x] 你的第一个 Web 组件

[ ]React 中最开始需要关注的生命周期

[ ]React 一个组件集合的简单交互

[ ]React 开始一个项目的一点建议

[ ]React 简单的项目结构组织

五、React 中最开始需要关注的生命周期

其实在学习 React 之前,就应该了解目前前端推荐的是组件化开发的方式,React 是让组件化更加简单的库。那么组件开发必不可少的就是生命周期,说直白一点就是运行组件的过程是 React 来做,运行过程中需要有一些代码钩子来让我们去调用,在组件执行的某一个地方去执行我们自己写的代码。这里先介绍拥有的生命周期钩子,下面的方法 constructorrender 不属于生命周期,我按功能分类了一下,也就是学习的时候不一定要按部就班,应该以学习之后能真正写一些东西为目标:

(1) 与组件挂载相关的方法,包括构造函数

constructor

componentWillMount

componentDidMount

componentWillUnmount

最常用的生命周期应该是最后 2 个,constructorcomponentWillMount 目前先理解成能满足的功能大体相同,如果这里解释太复杂不太好。

对于最开始关注的是:this.state 的初始化以及 ajax 在哪里请求。

this.state 在 constructor 进行初始化,ajax 推荐在 componentDidMount 中进行请求。

componentDidMount 就是在组件已经挂载到 DOM 中后的钩子,可以理解为 jQuery 中提供的 ready 方法。

componentWillUnmount 是在组件即将被卸载前一刻的钩子,一般用于取消 componentDidMount 中订阅的事件等作用,清理一些不要的变量等,避免内存泄漏。

下面通过一个简单的例子说明一下:

先有一个 foods.json 文件来模拟请求的后台数据。

[
    {
        "id": 1,
        "name": "香蕉"
    },
    {
        "id": 2,
        "name": "苹果"
    },
    {
        "id": 3,
        "name": "猕猴桃"
    }
]
// 1. 挂载相关的生命周期
class CycleMount extends React.Component {
    constructor() {
        super();
        this.state = {
            foods: []
        };

        console.log("1. constructor 执行了...");
    }
    componentDidMount() {
        // 这里使用原生的 fetch API 进行 ajax 请求,你也可以使用 $.ajax 进行请求,原理是一样的,重点是关注 setState 的地方
        fetch("/mock/foods.json",
            {
                method: "GET",
                headers: new Headers({
                    "Accept": "application/json"
                })
            }
        ).then(dataResult => {
            if(dataResult.status === 200) {
                return dataResult.json();
            } else {
                return [];
            }
        }).then(data => {
            // 这里的 data 就是 foods.json 里面的数据
            // 调用 setState 来更新 render 里面调用的 this.state 的值
            this.setState({
                foods: data
            });
        });

        console.log("2. componentDidMount 执行了...");
    }
    render() {
        // foods 是一个数组,map 方法是数组自带的方法,可以查询相关 api
        const foodItems = 
            this.state.foods.map(food => {
                return (
  • {food.name}
  • ); }); // 这里是返回的最终组件结构 return (
      {foodItems}
    ); } }

    上面有了完整的注释,也能看到基本上项目中可能会将代码写到何处,我也打了两个日志,来识别到底是谁先执行,结果可以自己运行一下,执行顺序就是我标记的1,2。

    好了,基本的学习了,可以自己动手试试订阅一个事件,然后在卸载的时候取消这个事件。

    (2) 优化相关

    shouldComponentUpdate

    这个方法比较重要,但是我这里不会介绍得太过于复杂,太复杂只会让重要的部分不那么突出。这个方法的返回值是一个 boolean 类型,分别代码的意义:

    true 组件应该更新,执行 render 方法以及相关生命周期;

    false 组件状态没有更新,不执行 render 等方法,意味着网页界面不会改变。

    那么它直观上的作用是能够通过返回值来决定界面是否改变,实际的意义就是当我们知道当前 oldState = this.state 的值和新的 newState = this.state 值完全相等的时候(或者是新传入的 props)就不用再浪费性能去重新渲染组件了。

    API 上的定义是这样的:

    /* nextProps: 新的 props, nextState: 新的 state */
    shouldComponentUpdate(nextProps, nextState): boolean

    举个例子来直观说明一下:

    class ComponentOptimize extends React.Component {
        state = {
            count: 0
        };
        shouldComponentUpdate(nextProps, nextState) {
            // 当 count > 10 的时候就不能再重新渲染组件了
            if(nextState.count > 10) {
                return false;
            }
    
            return true;
        }
        handleUpdateCount() {
            console.log("我点了一下哦!");
            this.setState(prevState => {
                return {
                    count: prevState.count + 1
                };
            });
        }
        render() {
            return (
                

    {this.state.count}

    ); } }

    你会发现 10 过后界面就没有再更新过了,这样应该很直观了。

    (3) Props 相关的生命周期

    componentWillReceiveProps

    这个主要是在组件的 props 传入新的值后被调用,不管是不是传的一样的值或者 shouldComponentUpdate 返回了 false,看下例子吧:

    class Cat extends React.Component {
        componentWillReceiveProps(nextProps) {
            console.log("改一次我执行一次!");
        }
        shouldComponentUpdate(nextProps, nextState) {
            // 改的名字一样的时候
            return this.props.name !== nextProps.name;
        }
        render() {
            console.log("猫改了一次名字!");
            return (
                

    我有新名字了!{this.props.name}

    ); } } class App extends React.Component { state = { catName: "噜噜" }; handleChangeCatName() { const catNames = ["噜噜", "小白", "小黄", "小黑", "皮卡丘"]; const catIndex = this.getSomeOneIndex(); this.setState({ catName: catNames[catIndex] }); } getSomeOneIndex() { return Math.floor(Math.random() * 5 + 0); } render() { return (
    {/* 给 Cat 传新的名字 */}
    ); } }

    最后肯定每次点击按钮都会输出这句的结果 console.log("改一次我执行一次!");

    (4) 更新组件相关

    componentWillUpdate

    componentDidUpdate

    因为都是讲解 API,所以国际惯例的先看下 API 的定义吧:

    // 组件更新前执行
    componentWillUpdate(nextProps, nextState)
    // 组件更新后执行
    componentDidUpdate(prevProps, prevState)

    可以从定义中看出,它们都接受了两个参数:props && state,不过看变量前缀能够联想点什么。

    暂时想不到什么实际项目的例子,随便假设点内容吧。不过这里需要注意的地方是:

    1. 这两个方法里面都不要调用 setState!

    2. 第一次初始化组件 render 的时候不会执行

    3. shouldComponentUpdate 返回 false 不会执行

    第一条的原因:容易形成一个递归的调用,不作就不会死...所以尽量不要在这里调~目前还没有碰到需要在这里调的需求。
    第二条的原因:额,说好的更新才调,初始化不调用是符合逻辑的。
    第三条的原因:额,这 2 个钩子是与组件更新相关的,所以也符合逻辑的,组件是否更新就是靠 shouldComponentUpdate 返回值。

    在上面 Cat 的例子中加入下面的代码可以看下结果:

    componentWillUpdate() {
        console.log("componentWillUpdate 执行了!")
    }
    componentDidUpdate() {
        console.log("componentDidUpdate 执行了!")
    }

    (5)组件错误

    componentDidCatch

    就是在组件发生异常的时候可能会被调用的钩子,需要注意的有下面的地方:

    只能在父级组件捕获子组件的异常;

    如果异常被 try...catch 包裹父级组件的钩子就不会执行了。

    看个例子吧:

    class Cat extends React.Component {
        componentWillReceiveProps(nextProps) {
            // 这里手动抛一个异常,触发我们的钩子 componentDidCatch
            throw new Error("miao miao~");
        }
        render() {
            let miao = this.props.name;
    
            return (
                
    {miao}
    ); } } class App extends React.Component { state = { catName: "噜噜", isError: false, }; handleChangeCatName() { const catNames = ["噜噜", "小白", "小黄", "小黑", "皮卡丘"]; const catIndex = this.getSomeOneIndex(); this.setState({ catName: catNames[catIndex] }); } getSomeOneIndex() { return Math.floor(Math.random() * 5 + 0); } componentDidCatch(error, info) { console.log(error, info); if(error) { // 如果有错误信息,就重新渲染一下组件,可能是更好的交互 this.setState({ isError: true }); } } render() { return (
    {!this.state.isError ? :

    不要奴才给我取名字了!

    }
    ); } }

    (6) 渲染相关

    render

    额...这个不想写了,先睡觉吧~应该写了这么多个小例子也差不多了~可以动手试试哦!还不清楚的可以 Google 一下,你就知道。

    生命周期很重要,其实学到这里也差不多可以上手写点项目熟练一下了,其他的更多是思维和编程方面的东西,周期的篇幅多带带来一篇吧~其他主题之后再继续吧!

    文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/93570.html

    相关文章

    • React 导读(四)

      摘要:一前言在导读三中介绍了项目的背景功能需求项目结构以及组件的划分层次,接下来我们就来看下实际的代码,这一篇文章会主要分享用到的基础组件的封装。 一、前言 在 React 导读(三) 中介绍了项目的背景、功能需求、项目结构以及组件的划分层次,接下来我们就来看下实际的代码,这一篇文章会主要分享用到的基础组件的封装。 二、基础组件设计 我们在设计组件之前本来是有一个流程和过程的,这里我写的组件...

      cooxer 评论0 收藏0
    • React 导读(一)

      摘要:需要有一定的基础和的使用经验。这就是属性的作用。方法接收一个新对象来重新赋值。也接收一个函数,这个回调函数这里我默认有一个参数,表示之前的的值,这个函数的返回值就是最新的。但是不同的是在组件内部是只读的。 前言 写这篇文章的主要目标是让初学者更快的上手 React 的项目开发,能有一个循循渐进的理解过程。需要有一定的 JavaScript 基础和 NPM 的使用经验。不多说了,下面会按...

      kumfo 评论0 收藏0
    • React 导读(三)

      摘要:场景为了更清晰的安排年前年后的工作和值班,现在要对过年期间人员请假的情况进行统计,并且进行一个简单的管理。我们现在来订阅一个名为的事件,用来表示表格中需要展示每条数据。 前言 React 导读(一)React 导读(二) 在之前 2 篇文章中中学习到了写第一个 Web 组件以及常用的生命周期函数的使用,这篇文章将继续之前的目录,开始新的知识点补充: [x] React 如何编写 He...

      zzir 评论0 收藏0
    • 《深入理解ES6》笔记——导读

      摘要:最近买了深入理解的书籍来看,为什么学习这么久还要买这本书呢主要是看到核心团队成员及的创造者为本书做了序,作为一个粉丝,还是挺看好这本书能给我带来一个新的升华,而且本书的作者也非常厉害。 使用ES6开发已经有1年多了,以前看的是阮一峰老师的ES6教程,也看过MDN文档的ES6语法介绍。 最近买了《深入理解ES6》的书籍来看,为什么学习ES6这么久还要买这本书呢?主要是看到Daniel A...

      Godtoy 评论0 收藏0

    发表评论

    0条评论

    最新活动
    阅读需要支付1元查看
    <