掘金最污的 React16.x 图文视频教程(2万5千字长文-慎入)

59,999 阅读1小时+

React免费视频教程

这是一门免费课程,写文章和录制视频这个我花了1个半月时间,如果你觉的不错可以给一个赞。文章和视频中会详细讲解React的基础知识,React版本是16x,也是目前最新版本(我课程录制开始的日期是2019年5月4日)。今年的目标是录制100集前端免费视频教程,可能大部分都会在React框架上,毕竟它是现在最火的前端框架,也是前端必会的一个框架。

我们采用最新的React16.8版本进行讲解,我相信很多人应该也会使用React,但是你可能学的并不是很系统,不妨跟着技术胖来一次详细的学习吧。

已更新完成........附上文章视频列表。

视频列表

  1. React课程前言(315)

  2. React简介和Vue对比(314)

  3. React开发环境搭建(313)

  4. 脚手架生成的项目目录介绍 (312)

  5. HelloWorld和组件的讲解 (311)

  6. React中JSX语法简介 (310)

  7. React实例-小姐姐服务菜单 (309)

  8. React实例-宝剑磨的好,理论不能少(308)

  9. React实例-老板我要加个钟(307)

  10. React实例-宝剑虽然好 老腰受不了(306)

  11. React进阶-JSX防踩坑的几个地方(305)

  12. React进阶-Simple React Snippets(304)

  13. React进阶-组件的拆分(303)

  14. React进阶-父子组件的传值(303)

  15. React进阶-单项数据流和其他(302)

  16. React高级-调试工具的安装及使用(301)

  17. React高级-PropTypes校验传递值(300)

  18. React高级-ref的使用方法(299)

  19. React高级-生命周期讲解-1(298)

  20. React高级-生命周期讲解-2(297)

  21. React高级-生命周期讲解-3(296)

  22. React高级-生命周期改善程序性能(295)

  23. React高级-axios数据请求(294)

  24. React高级-Axios请求EasyMock(293)

  25. React高级-用CSS3实现react动画(292)

  26. React高级-CSS3的keyframes动画(291)\

  27. React高级-react-transition-group(290)

  28. React高级-多DOM动画制作和编写(289)

第01节:React课程前言

很高兴你能来到这里学习React.js技术,这是课程的第一节,主要介绍一下小伙伴们常问的一些问题,虽然废话很多,但是还是建议你可以花几分钟看完这节视频。

技术胖的React交流Q群:159579268

React简介

首先不能否认React.js是全球最火的前端框架(Facebook推出的前端框架),国内的一二线互联网公司大部分都在使用React进行开发,比如阿里、美团、百度、去哪儿、网易 、知乎这样的一线互联网公司都把React作为前端主要技术栈。

React的社区也是非常强大的,随着React的普及也衍生出了更多有用的框架,比如ReactNativeReact VR。React从13年开始推广,现在已经推出16RC(React Fiber)这个版本,性能和易用度上,都有很大的提升。

React优点总结

  • 生态强大:现在没有哪个框架比React的生态体系好的,几乎所有开发需求都有成熟的解决方案。

  • 上手简单: 你甚至可以在几个小时内就可以上手React技术,但是他的知识很广,你可能需要更多的时间来完全驾驭它。

  • 社区强大:你可以很容易的找到志同道合的人一起学习,因为使用它的人真的是太多了。

需要的前置知识

  • JavaScript基础:如果能回ES6就更好了,因为我们尽量在课程中使用ES6的语法编写案例。

  • npm基础:你需要会使用npm的包管理,其实这个不会也没事,反正课程中都会讲解。

讲授方式和学习要领

  • 学习这套视频你完全不用记笔记,只要专心的听课,笔记技术胖已经为你准备好了文字版在每个视频下方。

  • 代码全部手写:代码全部进行手写,不做PPT式讲解,不做粘贴复制,你只要认真看,肯定学的会,不会有坑让你爬不上来。

  • 和3000名小伙伴一起学习: 群已经开放了,你可以直接进入QQ群,大家都是一起学习的,有什么问题可以一起讨论。

视频更新频率

这个视频每周更新三集,所以请小伙伴们收藏本网页,或者进入群学习,只要更新内容,群里都会进行通知。可以保证你及时的学习。

技术胖还是个一线程序员,平时加班也不少,所以有时候会更新不及时,还请大家谅解。

声明:课程借鉴了《深入浅出React和Redux》这本书,但也加入了自己的理解,更不会单纯的抄袭本书的任何话语和章节,如果引用本书话语,都会全部标出,以示对版权的尊重(其实我就是看着这本书学习的,然后录制的课程)。

如果你觉的看书更好,可以买一本学习。

加QQ群 一起学习

为了大家能更好的一起学习,技术胖同样也建立了QQ群,如果学习中遇到什么困难,可以进群提问,相信群里有很多人可以为你解答问题。

QQ群 :524520566 (3000人大群,入群请正确回答问题,答案请全部小写)

群里只讨论技术问题,禁止闲聊。

如果你在学习中有什么问题,还可以在文章下方进行留言,技术胖会尽快回复你的问题。

由于个人能力有限,在讲解过程中有不对之处,希望大家能在文章底部进行留言勘误校正,技术胖在先在这里抱手感谢。

第02节:React简介和Vue对比

这节课简单介绍一下React框架,并通过介绍,引出一个争执很多的话题,到底什么时候用React.js?什么时候用Vue.js?其实这节课也是偏重于理论的,但是我觉的有必要单独拿出来一节课说一说,因为有很多小伙伴还在犹豫,我已经会了Vue,还有没有必要学习React?答案是肯定的,那就是一定要学。因为这套课可能更多的面向新手,所以必要的理论也是不能缺少的。

技术胖的React交流Q群:159579268

React简介

如果你进入官方网站,只会看到一句简单的介绍:

A JavaScript library for building user interfaces (用于构建用户界面的JavaScript库)

就是这样简单的一句话,显得朴实无华,但当我每次看到时都感到它的霸气侧漏,肃然起敬。越是伟大的东西,越让人感到谦卑。

毒鸡汤

作为一个程序员,任何时候,都不要瞧不起别人…鸟活着时,吃蚂蚁;鸟死后,蚂蚁吃鸟。一棵树可以制成一百万根火柴,烧光一百万棵树只需一根火柴。所以不要瞧不起任何人!你瞧不起别人时,只不过别人不和你计较!花,姹紫嫣红,却只是昙花一现: 树,朴素寻常,却可以百岁长青。活着,低调做人。因为作为一名程序员,就算你想高调,你有时间和金钱吗?别做梦了,好好学习吧!

React三大体系

React三大体系图

这个学习也是有一个层次的,需要你先学会React.js的基本知识,然后再学习ReactNative,这样你的学习难度会大大降低。我的目标也是这样的,先讲解React.js基础,然后基础打好了,开始学习ReactNatvie。所以这个视频的周期还是比较长的,需要你多些耐心的学习。

正式简介

ReactJS是由Facebook在2013年5月推出的一款JS前端开源框架,推出式主打特点式函数式编程风格。值得一说的是,到目前为止ReactJS是世界上使用人数最多的前端框架,它拥有全球最健全的文档和社区体系。我们这里学习的是React Fiber版本,也就是React16这个版本,这个版本算是一个大升级,增加了很多新的特性,这些特性我都会在以后的课程中给大家一点点讲解。

ReactJS的官方网站为:reactjs.org

如果你是英文很好的同学,我建议你一直阅读React官方文档,这个文档我相信一定可以超过80%现在市面上的React书籍,详细程度就更不用多说了,怎么说人家是官方文档,是书籍编写者的写作大纲哦。(包括我的文章,一定不如官方文档好)

React和Vue的对比

这是前端最火的两个框架,虽然说React是世界使用人数最多的框架,但是就在国内而言Vue的使用者很有可能超过React。两个框架都是非常优秀的,所以他们在技术和先进性上不相上下。

那个人而言在接到一个项目时,我是如何选择的那?React.js相对于Vue.js它的灵活性和协作性更好一点,所以我在处理复杂项目或公司核心项目时,React都是我的第一选择。而Vue.js有着丰富的API,实现起来更简单快速,所以当团队不大,沟通紧密时,我会选择Vue,因为它更快速更易用。(需要说明的是,其实Vue也完全胜任于大型项目,这要根据自己对框架的掌握程度来决定,以上只是站在我的知识程度基础上的个人总结)

总结

我相信大家通过这节课的学习,对React一定有了一个直观的概念。下节课开始我们就要动手开发了,小伙伴们加油了。

第03节:React开发环境搭建

通过两节课的理论学习,这节终于可以进入操作环节了,其实技术胖早已经迫不及待了。讲理论就放佛认识一个美女,缺只能让你看,剩下啥都做不了一样。了解我的小伙伴都知道,我一定不是这种性格。这节课就让我们一起动手,把React的开发环境搭建好。在搭建React开发环境前需要你安装Node,如果你已经安装了可以省略这些步骤。

技术胖的React交流Q群:159579268

安装Node.js

使用React.js是可以用最原始的<Script>标签进行引入的,但是这实在是太low了,工作中也不会有这种形式进行引入。所以在学习的时候,我们就采用脚手架形式的安装。这就需要我们安装Node.js,用里边的npm来进行安装。

安装Node只需要进入Node网站,进行响应版本的下载,然后进行双击安装就可以了。

Node中文网址:nodejs.cn/ (建议你在这里下载,速度会快很多)

需要你注意的是,一定要正确下载对应版本,版本下载错误,可是没有办法使用的哦。

Node.js 安装好以后,如果是Windows系统,可以使用 Win+R打开运行,然后输入cmd,打开终端(或者叫命令行工具)。

输入代码:

node -v 

如果正确出现版本号,说明Node安装成功了,需要说明的是,你的版本号可能跟我视频中的有所不同,这无关紧要。

然后再输入代码:

npm -v

如果正确出现版本号,说明npm也是没问题的,这时候我们的Node.js安装就算完成了。

脚手架的安装

Node安装好之后,你就可以使用npm命令来安装脚手架工具了,方法很简单,只要打开终端,然后输入下面的命令就可以了。

npm install -g create-react-app

create-react-app是React官方出的脚手架工具,其实有很多第三方的脚手架工具,也有很多优秀的。但是作为初学者为了减少踩坑,所以我们使用官方的脚手架。

创建第一个React项目

脚手架安装好以后,就可以创建项目了,我们在D盘创建一个ReactDemo文件夹,然后进入这个文件夹,创建新的React项目。

D:  //进入D盘
mkdir ReactDemo  //创建ReactDemo文件夹
create-react-app demo01   //用脚手架创建React项目
cd demo01   //等创建完成后,进入项目目录
npm start   //预览项目,如果能正常打开,说明项目创建成功

其实这些操作只需要再终端中输入就可以了。等到浏览器可以打开React网页,并正常显示图标后,说明我们的环境已经全部搭建完成了。

毒鸡汤 亲爱的程序员: 如果你安装失败了,你不要惧怕,毕竟怕啥来啥。 你要相信只要你全力以赴,就没有你搞不砸的事情。

你可以试着换成手机WIFI热点,再来一遍上边的步骤,没准你流量费花了,就安装成功了那。你也可以在群里留言,技术胖会全力帮助你。

总结:这节课开始技术胖希望你能跟着我动手作一作,因为你不动手永远学不会。技术胖没有任何别的目的,真心希望你可以学会。动手把环境搭建好,否则下节课你就没办法练习了。

第04节:脚手架生成的项目目录介绍

用脚手架生成目录后,需要对目录有个基本的认识。最起码知道都是作什么用的,否则我们如何编写程序那?打个比喻:你知道了一个特别好的娱乐场所,你一直很向往,想去体验一把,可是你不了解行情和规矩,那最多你也只能去泡泡澡,吃吃自助餐了。我们现在就是这种情况,所以这节课将带你浏览一下React脚手架生成目录和文件的作用。

技术胖的React交流Q群:159579268

项目根目录中的文件

先从进入项目根目录说起,也就是第一眼看到的文件(版本不同,可能稍有不同)

  • README.md :这个文件主要作用就是对项目的说明,已经默认写好了一些东西,你可以简单看看。如果是工作中,你可以把文件中的内容删除,自己来写这个文件,编写这个文件可以使用Markdown的语法来编写。

  • package.json: 这个文件是webpack配置和项目包管理文件,项目中依赖的第三方包(包的版本)和一些常用命令配置都在这个里边进行配置,当然脚手架已经为我们配置了一些了,目前位置,我们不需要改动。如果你对webpack了解,对这个一定也很熟悉。

  • package-lock.json:这个文件用一句话来解释,就是锁定安装时的版本号,并且需要上传到git,以保证其他人再npm install 时大家的依赖能保证一致。

  • gitignore : 这个是git的选择性上传的配置文件,比如一会要介绍的node_modules文件夹,就需要配置不上传。

  • node_modules :这个文件夹就是我们项目的依赖包,到目前位置,脚手架已经都给我们下载好了,你不需要单独安装什么。

  • public :公共文件,里边有公用模板和图标等一些东西。

  • src : 主要代码编写文件,这个文件夹里的文件对我们来说最重要,都需要我们掌握。

public文件夹介绍

这个文件都是一些项目使用的公共文件,也就是说都是共用的,我们就具体看一下有那些文件吧。

  • favicon.ico : 这个是网站或者说项目的图标,一般在浏览器标签页的左上角显示。

  • index.html : 首页的模板文件,我们可以试着改动一下,就能看到结果。

  • mainifest.json:移动端配置文件,这个会在以后的课程中详细讲解。

src文件夹介绍

这个目录里边放的是我们开放的源代码,我们平时操作做最多的目录。

  • index.js : 这个就是项目的入口文件,视频中我们会简单的看一下这个文件。

  • index.css :这个是index.js里的CSS文件。

  • app.js : 这个文件相当于一个方法模块,也是一个简单的模块化编程。

  • serviceWorker.js: 这个是用于写移动端开发的,PWA必须用到这个文件,有了这个文件,就相当于有了离线浏览的功能。

总结:建议你这节课要看视频进行学习,视频会讲的详细一点,而且更有层次,看文章你可能学不会。

第05节:HelloWorld和组件的讲解

这节课先把src目录里的文件全部删除,我们一点点写一个·HelloWorld·程序,并通过编写这个程序了解一下什么是React中的组件化编程。

入口文件的编写

写一个项目的时候一般要从入口文件进行编写的,在src目录下,新建一个文件index.js,然后打开这个文件。

写入下面4行代码:

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />,document.getElementById('root'))

上面的代码,我们先引入了React两个必要的文件,然后引入了一个APP组件,目前这个组件还是没有的,需要一会建立。然后用React的语法把APP模块渲染到了root ID上面.这个rootID是在public\index.html文件中的。

这样入口文件就写好了,这时候我们就需要写APP组件了。

app组件的编写

现在写一下App组件,这里我们采用最简单的写法,就输出一个Hello JSPang,就可以了。

import React, {Component} from 'react'

class App extends Component{
    render(){
        return (
            <div>
                Hello JSPang
            </div>
        )
    }
}
export default App;

这里有一个难点,就是:

import React, {Component} from 'react'

这其实是ES6的语法-解构赋值,如果你分开写就比较清楚了,你可以把上面一行代码写成下面两行.

import React from 'react'
const Component = React.Component

如果你对ES6语法不熟悉,你完全可以使用这种形式来进行编写。

当我们这两个文件都编写完成后,可以在终端使用npm start命令,来看一下我们编写的结果了。

**总结:**React的主要优势之一就是组件化编写,这也是现代前端开发的一种基本形式。所以我们在学习React的时候就要多用这种思想,只有不断练习,我们才能在工作中得心应手,轻松自如。小伙伴们也动手作一下吧。

第06节:React中JSX语法简介

上节课已经接触到了JSX语法,看起来跟html标签几乎一样,事实也是如此。JSX语法确实也有很多需要注意的事项,但是对于初学者学太多反而不好。所以这节课我们作一个最简单的JSX语法介绍。

JSX简介

JSX就是Javascript和XML结合的一种格式。React发明了JSX,可以方便的利用HTML语法来创建虚拟DOM,当遇到<,JSX就当作HTML解析,遇到{就当JavaScript解析.

比如我们写一段JSX语法

<ul className="my-list">
    <li>JSPang.com</li>
    <li>I love React</li>
</ul>

比如我们以前写一段代码JS代码:

var child1 = React.createElement('li', null, 'JSPang.com');
var child2 = React.createElement('li', null, 'I love React');
var root = React.createElement('ul', { className: 'my-list' }, child1, child2);

从代码量上就可以看出JSX语法大量简化了我们的工作。

组件和普通JSX语法区别

这个说起来也只有简单的一句话,就是你自定义的组件必须首写字母要进行大写,而JSX是小写字母开头的。

这个也算是一个比较重要的知识点吧。

JSX中使用三元运算符

在JSX中也是可以使用js语法的,这节课我们先简单讲解一个三元元算符的方法,见到了解一下。

import React from 'react'
const Component = React.Component


class App extends Component{
    render(){
        return (
            <ul className="my-list">
                <li>{false?'JSPang.com':'技术胖'}</li>
                <li>I love React</li>
            </ul>
        )
    }
}

export default App;

总结:通过这节课的简单学习,小伙伴们一定对JSX语法有个简单的了解,其实作为一个初学者,我们先知道这么多就足够了。随着课程以后我们会继续深入讲解。

第07节:React实例-小姐姐服务菜单

通过六节的学习,已经对React有了基本的认识。最好的学习就是在实战中的成长了,我们开始以作一个《小姐姐服务菜单》的应用,练习以前所学的知识和学习新知识。当然这个视频不是教大家作CSS的,所以我就不进行样式布局了。

新建小姐姐组件

现在SRC的目录下面,新建一个文件Xiaojiejie.js文件,然后写一个基本的HTML结构。代码如下:

import React,{Component} from 'react'

class Xiaojiejie extends Component{
    render(){
        return  (
            <div>
               <div><input /> <button> 增加服务 </button></div>
               <ul>
                   <li>头部按摩</li>
                   <li>精油推背</li>
               </ul> 
            </div>
        )
    }
}
export default Xiaojiejie 

这个文件现在还没有什么功能,只是写完了一个小组件。然后我们把入口文件的<App />组件换成Xiajiejie组件。

组件外层包裹原则

这是一个很重要的原则,比如上面的代码,我们去掉最外层的<Div>,就回报错,因为React要求必须在一个组件的最外层进行包裹。

错误代码(因为外边少了最外层的包裹):


import React,{Component} from 'react'

class Xiaojiejie extends Component{
    render(){
        return  (
               <div><input /> <button> 增加服务 </button></div>
               <ul>
                   <li>头部按摩</li>
                   <li>精油推背</li>
               </ul> 
        )
    }
}
export default Xiaojiejie 

所以我们在写一个组件的时候,组件的最外层都需要有一个包裹。

Fragment标签讲解

加上最外层的DIV,组件就是完全正常的,但是你的布局就偏不需要这个最外层的标签怎么办?比如我们在作Flex布局的时候,外层还真的不能有包裹元素。这种矛盾其实React16已经有所考虑了,为我们准备了<Fragment>标签。

要想使用<Fragment>,需要先进行引入。

import React,{Component,Fragment } from 'react'

然后把最外层的<div>标签,换成<Fragment>标签,代码如下。

import React,{Component,Fragment } from 'react'

class Xiaojiejie extends Component{
    render(){
        return  (
            <Fragment>
               <div><input /> <button> 增加服务 </button></div>
               <ul>
                   <li>头部按摩</li>
                   <li>精油推背</li>
               </ul> 
            </Fragment>
        )
    }
}
export default Xiaojiejie 

这时候你再去浏览器的Elements中查看,就回发现已经没有外层的包裹了。

**总结:**下节课我们要实现增加服务项,期待下一集和技术胖一起开车吧。

第08节:React实例-宝剑磨的好,理论不能少

这节课我们主要了解一下React中的响应式设计原理和数据的绑定方法,俗话说的好:"宝剑磨的好,理论不能少"。这节课我们不仅要编写效果,还要讲理论,这节课很重要,因为这涉及React中的设计思想和你以后的编程思路。

响应式设计和数据的绑定

React不建议你直接操作DOM元素,而是要通过数据进行驱动,改变界面中的效果。React会根据数据的变化,自动的帮助你完成界面的改变。所以在写React代码时,你无需关注DOM相关的操作,只需要关注数据的操作就可以了(这也是React如此受欢迎的主要原因,大大加快了我们的开发速度)。

现在的需求是增加小姐姐的服务项,就需要先定义数据。数据定义在Xiaojiejie组件中的构造函数里constructor

//js的构造函数,由于其他任何函数执行
constructor(props){
    super(props) //调用父类的构造函数,固定写法
    this.state={
        inputValue:'' , // input中的值
        list:[]    //服务列表
    }
}

React中的数据绑定和Vue中几乎一样,也是采用字面量(我自己起的名字)的形式,就是使用{}来标注,其实这也算是js代码的一种声明。比如现在我们要把inputValue值绑定到input框中,只要写入下面的代码就可以了。其实说白了就是在JSX中使用js代码。

<input value={this.state.inputValue} /> 

现在需要看一下是不是可以实现绑定效果,所以把inputValue赋予一个'jspang',然后预览看一下效果。在这里我们并没有进行任何的DOM操作,但是界面已经发生了变化,这些都时React帮我们作的,它还会自动感知数据的变化。

绑定事件

这时候你到界面的文本框中去输入值,是没有任何变化的,这是因为我们强制绑定了inputValue的值。如果要想改变,需要绑定响应事件,改变inputValue的值。比如绑定一个改变事件,这个事件执行inputChange()(当然这个方法还没有)方法。

<input value={this.state.inputValue} onChange={this.inputChange} />

现在还没有inputChange()这个方法,在render()方法的下面建立一个inputChange()方法,代码如下:

 inputChange(e){
        console.log(e);
    }

这时候会发现响应事件可以使用了,但是如何获得我们输入的值那,程序中输入下面的代码。

inputChange(e){
    console.log(e.target.value);
}

这时候控制台是可以打印出输入的值的,视频中会有演示。看到获得了输入的值,想当然的认为直接改变inputValue的值就可以了(错的).

inputChange(e){
    console.log(e.target.value);
    this.state.inputValue=e.target.value;
}

写完后再进行预览,会发现程序直接报错了(加项服务还真的有点难度哦,大宝剑不好作的...........)。

其实我们范了两个错误:

  1. 一个是this指向不对,你需要重新用bind设置一下指向(ES6的语法)。
  2. 另一个是React中改变值需要使用this.setState方法。

第一个错误很好解决,直接再JSX部分,利用bind进行绑定就好。

 <input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />

这步做完,我们还需要加入setState方法,改变值。代码如下:

inputChange(e){
    // console.log(e.target.value);
    // this.state.inputValue=e.target.value;
    this.setState({
        inputValue:e.target.value
    })
}

现在测试一下,输入框可以改变值了,其实这节课很重要,里边设计了React的重要思想,建议这节课可以反复多看两遍,虽然不难,但是这是一个最基本的思想的转变。下节课可要真的增加服务项目了。

第09节:React实例-老板我要加个钟

有了上节课的基础,这节课终于可以添加服务,为所欲为了,随意增加你想要的服务了。这节课我们就来增加一个躺式采耳服务,体验一把帝王级待遇。

让列表数据化

现在的列表还是写死的两个<li>标签,那要变成动态显示的,就需要把这个列表先进行数据化,然后再用javascript代码,循环在页面上。

我们先给上节课的list数组增加两个数组元素,代码如下:

constructor(props){
    super(props) //调用父类的构造函数,固定写法
    this.state={
        inputValue:'jspang' , // input中的值
        //----------主要 代码--------start
        list:['基础按摩','精油推背']   
        //----------主要 代码--------end
    }
}

有了数据后,可以在JSX部分进行循环输出,代码如下:

render(){
    return  (
        <Fragment>
            <div>
                <input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
                <button> 增加服务 </button>
            </div>
            <ul>
                {
                    this.state.list.map((item,index)=>{
                        return <li>{item}</li>
                    })
                }
            </ul>  
        </Fragment>
    )
}

完成上面的步骤,数据就不再是固定的了,而是动态管理的,也为我们接下来的添加打下了基础,剩下的步骤也显得很简单了。

增加服务选项

要增加服务选项,我们需要再增加按钮上先绑定一个方法this.addList(这个方法目前还没有,需要我们接下来建立).

<button onClick={this.addList.bind(this)}> 增加服务 </button>

接下来就是把this.addList方法,代码如下:

//增加服务的按钮响应方法
addList(){
    this.setState({
        list:[...this.state.list,this.state.inputValue]
    })

}

这里需要说的市...这个是ES6的新语法,叫做扩展运算符。意思就是把list数组进行了分解,形成了新的数组,然后再进行组合。这种写法更简单和直观,所以推荐这种写法。

写完上面的代码,应该就可以实现增加项目了,你可以试着增加一下自己喜欢的服务进去,比如"中药泡脚"........

解决key值错误

高兴的同时其实是有一些隐患的,打开浏览器的控制台F12,可以清楚的看到报错了。这个错误的大概意思就是缺少key值。就是在用map循环时,需要设置一个不同的值,这个时React的要求。我们可以暂时用index+item的形式来实现。

<ul>
    {
        this.state.list.map((item,index)=>{
            return <li key={index+item}>{item}</li>
        })
    }
</ul>  

这样就解决了这个隐患,现在就可以舒服的享受帝王级的服务了。

第10节:React实例-宝剑虽然好 老腰受不了

添加服务虽然很美妙,但是有时候也需要有些节制。这节课就学习如何删除一个服务选项。需求是这样的,当点击已经有的选项后,我们就进行删除。如果使用原生的js来写,这是非常麻烦的,但是有了React后就变的简单了。

数组下标的传递

如果要删除一个东西,就要得到数组里的一个编号,这里指下标。传递下标就要有事件产生,先来绑定一个双击事件.代码如下:

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <li 
                    key={index+item}
                    onClick={this.deleteItem.bind(this,index)}
                >
                    {item}
                </li>
            )
        })
    }
</ul>  

为了看着更清晰,我们在return部分加了()这要就可以换行编写JSX代码了.在onClick我们绑定了deleteItem方法.

编写deleteItem方法

绑定做好了,现在需要把deleteItem,在代码的最下方,加入下面的代码.方法接受一个参数index.

//删除单项服务
deleteItem(index){
    console.log(index)
}

这时候可以预览一下啊,已经在方法里获取到了下标.

正式删除数据

获得了数据下标后,删除数据就变的容易起来.先声明一个局部变量,然后利用传递过来的下标,删除数组中的值.删除后用setState更新数据就可以了.

//删除单项服务
deleteItem(index){
    let list = this.state.list
    list.splice(index,1)
    this.setState({
        list:list
    })
    
}

其实这里边是有一个坑的,有的小伙伴肯定会认为下面的代码也是正确的.

//删除单项服务
deleteItem(index){
    this.state.list.splice(index,1)
    this.setState({
        list:this.state.list
    }) 
}

记住React是禁止直接操作state的,虽然上面的方法也管用,但是在后期的性能优化上会有很多麻烦,所以一定不要这样操作.这也算是我React初期踩的比较深的一个坑,希望小伙伴们可以跳坑.

第11节:React进阶-JSX防踩坑的几个地方

上节课作完“大宝剑”菜单后,如果你跟着我做出来了,说明你的React已经入门了。也是一个好的开始,接下来的路虽然还很长,但会平坦的多。这节课就讲一下JSX语法中需要注意的几个小坑。

JSX代码注释

JSX中的代码注释是非常有讲究的,这个书上介绍的也非常少,所以在这里讲一下,因为技术胖在初学React在这里踩过坑。

我第一次写JSX注释,是直接这样写的,当然这样写是完全不对的。

<Fragment>
    //第一次写注释,这个是错误的
    <div>
        <input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
        <button onClick={this.addList.bind(this)}> 增加服务 </button>
    </div>

那写JSX的注释,可以有下面两种写法:

<Fragment>
    {/* 正确注释的写法 */}
    <div>
        <input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
        <button onClick={this.addList.bind(this)}> 增加服务 </button>
    </div>

如果你记不住,有个简单的方法,就是用VSCode的快捷键,直接按Ctrl+/,就会自动生成正确的注释了。

你可以把这个理解为,在jsx中写javascript代码。所以外出我们套入了{},然后里边就是一个多行的javascript注释。如果你要使用单行祝注释//,你需要把代码写成下面这样。

<Fragment>
    {
        //正确注释的写法 
    }
    <div>
        <input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
        <button onClick={this.addList.bind(this)}> 增加服务 </button>
    </div>

也就是你要进行换行,所以个人认为这种方法不太优雅,所以推荐第一种注释方法。

JSX中的class陷阱

比如要给朴素单纯的界面,加入黄色成分,让我们的文本框又粗又黄。我们先来错误演示。

第一步:先写一个CSS样式文件,在src目录下,新建一个style.css的样式文件。

.input {border:3px solid #ae7000}

第二步:在Xiaojiejie.js里引入,先用import进行引入,能用import引入,都是webpack的功劳。

import './style.css'

第三部:给JSX加入`class,注意下面的代码是错误的。

<input class="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />

虽然现在页面是可以正常显示结果的,但是你代开浏览器控制台会发现Warning警告。

index.js:1437 Warning: Invalid DOM property `class`. Did you mean `className`?
    in input (at Xiaojiejie.js:19)
    in div (at Xiaojiejie.js:18)
    in Xiaojiejie (at src/index.js:5)

意思就是要把class换成className,它是防止和js中的class类名 冲突,所以要求换掉。这也算是一个小坑吧。

JSX中的html解析问题

如果想在文本框里输入一个<h1>标签,并进行渲染。默认是不会生效的,只会把<h1>标签打印到页面上,这并不是我想要的。如果工作中有这种需求,可以使用dangerouslySetInnerHTML属性解决。具体代码如下:

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <li 
                    key={index+item}
                    onClick={this.deleteItem.bind(this,index)}
                    dangerouslySetInnerHTML={{__html:item}}
                >
                </li>
            )
        })
    }
</ul> 

上面的代码就可以实现html格式的输出。

JSX中<label>标签的坑

JSX中<label>的坑,也算是比较大的一个坑,label是html中的一个辅助标签,也是非常有用的一个标签。

先看下面的代码,我们在文本框前面加入一个<label>

<div>
    <label>加入服务:</label>
    <input className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
    <button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>

这时候想点击“加入服务”直接可以激活文本框,方便输入。按照html的原思想,是直接加ID就可以了。代码如下:

<div>
    <label for="jspang">加入服务:</label>
    <input id="jspang" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
    <button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>

这时候你浏览效果虽然可以正常,但console里还是有红色警告提示的。大概意思是不能使用for.它容易和javascript里的for循环混淆,会提示你使用htmlfor

<div>
    <label htmlFor="jspang">加入服务:</label>
    <input id="jspang" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
    <button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>

这时候代码就正确了,可以实现点击<label>后,激活<input>标签了。

这节算是我总结的一些JSX中的坑吧,总结出来,希望小伙伴们少踩这些坑,能快速上手React

第12节:React进阶-Simple React Snippets

这节课很短,但是我觉的有必要单独拿出一节来讲讲。在工作中你经常会看到程序老司机写代码是非常快的,甚至让你烟花缭乱,那他们真的是单身那么多年,练就了超级快手吗?当然不是,只是他们使用了快速生成插件,这节课我就向大家介绍一个vscode中的Simple React Snippets,有了这个插件,稍加练习,你也可以像老司机一样,拥有加藤鹰的圣手(如果不懂请自行搜索吧)。

安装Simple React Snippets

打开VSCode的插件查单,然后在输入框中输入Simple React Snippets,然后点击进行安装就可以了。

### 快速进行引入import

直接在vscode中输入imrc,就会快速生成最常用的import代码。

import React, { Component } from 'react';

快速生成class

在作组件的时候,都需要写一个固定的基本格式,这时候你就可以使用快捷键cc.插件就会快速帮我们生成如下代码:

class  extends Component {
    state = {  }
    render() { 
        return (  );
    }
}
 
export default ;

还有很多快捷键,我就没必要再这里唠叨了,如果你需要理解,打开插件的说明文件看一下就可以了。这个插件建议小伙伴们要熟练掌握,因为在老板眼里,代码编写速度的快慢直接跟我们的薪资有关,就是没什么关系。我们自己把时间剩下,去看小姐姐跳支舞不好吗?

第13节:React进阶-组件的拆分

现在的小姐姐服务菜单已经完美的制作好了,但是这从头到尾我们只用了一个组件,但是在实际工作中肯定是团队开发,我们会把一个大功能分成不同的组件。比如把文本框和按钮单独一个组件,把下面的服务列表单独一个组件,这涉及了一个组件拆分的能力和知识。这节课就把小姐姐服务菜单进行一个拆分。

新建服务菜单组件

src目录下,新建一个文件,这里就叫做XiaojiejieItem.js,然后先把最基础的结构写好(这里最好练习一下上节课学习的快捷键)。

import React, { Component } from 'react'; //imrc
class XiaojiejieItem  extends Component { //cc
   
    render() { 
        return ( 
            <div>小姐姐</div>
         );
    }
}
export default XiaojiejieItem;

写好这些代码后,就可以到以前写的Xiaojiejie.js文件中用import进行引入,代码如下:

import XiaojijieItem from './XiaojiejiItem'

### 修改Xiaojiejie组件

已经引入了新写的组件,这时候原来的代码要如何修改才能把新组件加入?

把原来的代码注释掉,当然你也可以删除掉,我这里就注释掉了,注释方法如下:


{/*
<li 
    key={index+item}
    onClick={this.deleteItem.bind(this,index)}
    dangerouslySetInnerHTML={{__html:item}}
>

</li>
*/ }

然后在最外层加入包裹元素<div>,为的是防止两个以上的标签,产生错误信息。

最后直接写入Xiaojiejie标签就可以了.

<XiaojiejieItem />

为了方便你练习,给出全部代码:


import React,{Component,Fragment } from 'react'
import './style.css'
import XiaojiejieItem from './XiaojiejieItem'

class Xiaojiejie extends Component{
//js的构造函数,由于其他任何函数执行
constructor(props){
    super(props) //调用父类的构造函数,固定写法
    this.state={
        inputValue:'' , // input中的值
        list:['基础按摩','精油推背']    //服务列表
    }
}

render(){
    return  (
        <Fragment>
            {/* 正确注释的写法 */}
<div>
    <label htmlFor="jspang">加入服务:</label>
    <input id="jspang" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
    <button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>
            <ul>
                {
                    this.state.list.map((item,index)=>{
                        return (
                            //----------------关键修改代码----start
                            <div>
                                <XiaojiejieItem />
                            </div>
                            //----------------关键修改代码----end
                           
                        )
                    })
                }
            </ul>  
        </Fragment>
    )
}

    inputChange(e){
        // console.log(e.target.value);
        // this.state.inputValue=e.target.value;
        this.setState({
            inputValue:e.target.value
        })
    }
    //增加服务的按钮响应方法
    addList(){
        this.setState({
            list:[...this.state.list,this.state.inputValue],
            inputValue:''
        })

    }
//删除单项服务
deleteItem(index){
    let list = this.state.list
    list.splice(index,1)
    this.setState({
        list:list
    })
    
}

}
export default Xiaojiejie 

这时候可以预览一下效果,虽然现在已经把组件进行了拆分,但是还全是显示的小姐姐,还没有实现传值,下节课我们主要实现一下React组件之间的传值(父组件向子组件传递数据)。

第14节:React进阶-父子组件的传值

通过上节课的学习,已经把"小姐姐"组件做了一个基本的拆分,但是还不能实现随着输入,显示出输入的内容。这里涉及的是父组件向子组件传值。然后点击删除,就相当于子组件向父组件传值。这节课就主要学习一下父子组件传值的一些技巧。

父组件向子组件传值

这里只介绍最实用的,最快速的上手方法。就是使用组件属性的形式父组件给子组件传值。比如:我们在<XiaojiejieItem>组件中加入content属性,然后给属性传递{item},这样就完成了父组件向子组件传值。

<XiaojiejieItem content={item} />

现在值已经顺利的传递了过去,这时候可以通过this.props.xxx的形式进行接受,比如传递过来的值,可以用如下代码进行接收。

import React, { Component } from 'react'; //imrc
class XiaojiejieItem  extends Component { //cc
   
    render() { 
        return ( 
            <div>{this.props.content}</div>
         );
    }
}
 
export default XiaojiejieItem;

修改完小姐姐子项的组件后,可以打开浏览器进行预览了。试着添加几个新的选项试一下,比如躺式采耳.....。

玩笑归玩笑,学到这里你要记住一点:父组件向子组件传递内容,靠属性的形式传递。

子组件向父组件传递数据

现在要作这样一个功能:点击组件中的菜单项后,删除改菜单项。在前边的课程中已经学习了这个知识,知识现在组件拆分了,就涉及了一个字组件向父组件传递数据的知识需要掌握。

先来绑定点击事件,这时候当然是要在XiaojiejieItem组件中绑定了,代码如下:

import React, { Component } from 'react'; //imrc
class XiaojiejieItem  extends Component { //cc
   
    render() { 
        return ( 
            <div onClick={this.handleClick}>{this.props.content}</div>
         );
    }

    handleClick(){
        console.log('撩拨了小姐姐')
    }
    
}
 
export default XiaojiejieItem;

这时候进行预览,打开F12,再点击服务菜单项,就会再console里显示出"撩拨了小姐姐"的字样。但是console里还有一个warning警告,这个警告我们见过,就是要求循环时必须设置key值。

修改XiaoJieJie组件的render代码如下:

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <XiaojiejieItem 
                key={index+item}  
                content={item} />
            )
        })
    }
</ul>  

绑定成功后,现在就要通过操作子组件删除父组件里的数据了。但是React有明确规定,子组件时不能操作父组件里的数据的,所以需要借助一个父组件的方法,来修改父组件的内容。其实在以前已经写了一个删除方法deleteItem,现在要作的就是子组件调用这个方法。

//删除单项服务
deleteItem(index){
    let list = this.state.list
    list.splice(index,1)
    this.setState({
        list:list
    })
    
}

获取数组索引下标

那现在问题来了,要删除就要知道索引值,还是需要通过父组件传递给子组件.这里还是通过props属性的形式进行传递。

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <XiaojiejieItem 
                key={index+item}  
                content={item}
                index={index} />
            )
        })
    }
</ul>  

然后修改XiaojiejieItem组件,在handleClick方法里,写入下面代码:

handleClick(){
    console.log(this.props.index)
}

这时候预览一下,你会发现点击后报错,错误还是我们的老朋友,没有bind(this)。那可以用以前的老方法绑定this.

return ( 
    <div onClick={this.handleClick.bind(this)}>
        {this.props.content}
    </div>
);

这样是可以决解的,但是肯定会有小伙伴说,我看别人不是这样写的,而是在构造函数里绑定的。(有言曰:构造函数中绑定性能会高一些,特别是在高级组件开发中,会有很大的作用)

constructor绑定this方法。


import React, { Component } from 'react'; //imrc
class XiaojiejieItem  extends Component { //cc
   //--------------主要代码--------start
   constructor(props){
       super(props)
       this.handleClick=this.handleClick.bind(this)
   }
   //--------------主要代码--------end
    render() { 
        return ( 
            <div onClick={this.handleClick}>
                {this.props.content}
            </div>
        );
    }
    handleClick(){
        console.log(this.props.index)
    }
}
 
export default XiaojiejieItem;

子组件调用父组件方法

如果子组件要调用父组件方法,其实和传递数据差不多,只要在组件调用时,把方法传递给子组件就可以了,记得这里也要进行this的绑定,如果不绑定子组件是没办法找到这个父组件的方法的。

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <XiaojiejieItem 
                key={index+item}  
                content={item}
                index={index}
                //关键代码-------------------start
                deleteItem={this.deleteItem.bind(this)}
                //关键代码-------------------end
                />
            )
        })
    }
</ul>  

传递后,在XiaojiejieItem组件里直接hi用就可以了,代码如下:

handleClick(){
    this.props.deleteItem(this.props.index)
}

到此为止,就算是实现了子组件向父组件传值。特别提醒:这节课是React体系中非常重要的一节课,小伙伴们可以多听几遍,并进行练习。因为真正的React开发工作,每天写的就是各种组件,传值是组件之间产生联系的必要一环,无法跳跃。所以一定要学好。

第15节:React进阶-单项数据流和其他

这节课我们讲一些理论性的东西,比如:React单项数据流、React同其他框架共同工作和函数式编程的一些概念,这节课可能会稍显无聊,因为都是理论的东西,但是这些知识无论是在面试中,还是在工作中都会经常遇到,所以也是跳不过去的一节课。

单项数据流

React的特性中有一个概念叫做“单项数据流”,可能刚刚接触React的小伙伴不太明白这个概念,还是拿出《小姐姐服务菜单》的Demo,来给大家讲解。比如我们在父组件中可以直接把this.state.list传递过来。例如下面代码:

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <XiaojiejieItem 
                key={index+item}  
                content={item}
                index={index}
                list={this.state.list}
                deleteItem={this.deleteItem.bind(this)}
                />
            )
        })
    }
</ul> 

其实这样传是没有问题的,问题是你只能使用这个值,而不能修改这个值,如果你修改了,比如我们把代码写成这样:

handleClick(){
    //关键代码——---------start
    this.props.list=[]
    //关键代码-----------end
    this.props.deleteItem(this.props.index)
}

就会报下面的错误;

TypeError: Cannot assign to read only property 'list' of object '#<Object>'

意思就是list是只读的,单项数据流。那如果要改变这里边的值怎么办?其实上节课已经讲过了,就是通过传递父组件的方法。

和其他框架配合使用

有小伙伴问我,Reactjquery能一起使用吗?

答案:是可以的,React其实可以模块化和组件化开发。看/public/index.html文件,代码如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
   
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <!--关键代码start-->
    <div id="root"></div>
     <!--关键代码end-->
   
  </body>
</html>

其实React只对这一个<div>,外边的其他DOM并不受任何影响,比如我们在它的下方再写一个<div>,然后查看效果。

<div id="root"></div>
<div style="color:red">今天过的好开心,服务很满意!</div>

你可以在其他的div里加入任何内容,但是这种情况很少,我也不建议这么使用。希望小伙伴们还是统一技术栈。

函数式编程

在面试React时,经常会问道的一个问题是:函数式编程的好处是什么?

  1. 函数式编程让我们的代码更清晰,每个功能都是一个函数。
  2. 函数式编程为我们的代码测试代理了极大的方便,更容易实现前端自动化测试。

React框架也是函数式编程,所以说优势在大型多人开发的项目中会更加明显,让配合和交流都得心应手。

总结:这节课虽然都是些理论知识,这些知识在面试中经常被问到,所以也是必须掌握的内容。

第16节:React高级-调试工具的安装及使用

已经可以简单的写一些React代码了,在视频中,我也是经常使用console.log这种很二的形式来调试程序。其实React在浏览器端是有一个调试工具的,这就是React developer tools,这个是React人必下的一个调试工具。这节课就主要学习一下React developer tools的下载和简单使用。

下载React developer tools

这个需要在chrome浏览器里进行,并且需要科学上网(这东西我不能在这里教,所以自行百度吧)。

  1. 点击浏览器地址栏最右边的...,然后选择更多工具,然后选择扩展程序

  2. 点击打开chrome网上应用店,直接在搜索框里搜索React,出现的第一个就是。

  3. 点击添加至Chrome,然后就是等待了..........

这段内容推荐看视频吧,其实并不复杂,但是都是需要上图的,我又懒得作图。

React developer tools的三种状态

React developer tools有三种颜色,三种颜色代表三种状态:

  1. 灰色: 这种就是不可以使用,说明页面不是又React编写的。
  2. 黑色: 说明页面是用React编写的,并且处于生成环境当中。
  3. 红色: 说明页面是用React编写的,并且处于调试环境当中。

React developer tools使用

打开浏览器,然后按F12,打开开发者工具,然后在面板的最后一个,你会返现一个React,这个就是安装的插件了。

在这里你可以清晰的看到React的结构,让自己写的代码更加清晰,你还可以看到组间距的数据传递,再也不用写console.log来测试程序了。

总结 : 这节课我们学习了React调试工具的安装和使用,在工作中一个前端的调试都是在这里进行的,所以拿出单独的一节课来讲一下。

第17节:React高级-PropTypes校验传递值

在父组件向子组件传递数据时,使用了属性的方式,也就是props,但“小姐姐服务菜单”的案例并没有任何的限制。这在工作中时完全不允许的,因为大型项目,如果你不校验,后期会变的异常混乱,业务逻辑也没办法保证。

PropTypes的简单应用

我们在Xiaojiejie.js组件里传递了4个值,有字符串,有数字,有方法,这些都是可以使用PropTypes限制的。在使用需要先引入PropTypes

import PropTypes from 'prop-types'

引入后,就可以在组件的下方进行引用了,需要注意的是子组件的最下面(不是类里边),写入下面的代码:

XiaojiejieItem.propTypes={
    content:PropTypes.string,
    deleteItem:PropTypes.func,
    index:PropTypes.number
}

具体意思,我会在视频中进行讲解,请观看视频。为了防止你的为止写错,我这里给出这个XiaojiejieItem.JS文件的代码。

import React, { Component } from 'react'; //imrc
import PropTypes from 'prop-types'

class XiaojiejieItem  extends Component { //cc
   
   constructor(props){
       super(props)
       this.handleClick=this.handleClick.bind(this)
   }
   
    render() { 
        return ( 
            <div onClick={this.handleClick}>
                {this.props.content}
            </div>
        );
    }

    handleClick(){
        
        this.props.deleteItem(this.props.index)
    }
    
}
 //--------------主要代码--------start
XiaojiejieItem.propTypes={
    content:PropTypes.string,
    deleteItem:PropTypes.func,
    index:PropTypes.number
}
 //--------------主要代码--------end
export default XiaojiejieItem;

这时候你在浏览器中查看效果,是什么都看不出来的,你需要修改一个错误的校验。比如我们把index改为必须是字符串。

index:PorpTypes.string

这时候浏览器的console里就会报错了,报错信息如下:

Warning: Failed prop type: Invalid prop `index` of type `number` supplied to `XiaojiejieItem`, expected `string`.
    in XiaojiejieItem (at Xiaojiejie.js:28)
    in Xiaojiejie (at src/index.js:5)

意思就是要求传递字符串,而我们却传递了数字过去,所以给了警告。

### 必传值的校验

比如现在我们加入一个avname的属性,并放入JSX中,就算不传递这个值也不会报错的。代码如下:

render() { 
    return ( 
        <div onClick={this.handleClick}>
            {this.props.avname}为你做- {this.props.content}
        </div>
    );
}

这时候代码是不会报错的,我们传不传无所谓。比如我们现在传一个属性过来。

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <XiaojiejieItem 
                key={index+item}  
                content={item}
                index={index}
                avname='波多野结衣'
                deleteItem={this.deleteItem.bind(this)}
                />
            )
        })
    }
</ul>  

这时候页面显示正常了,但是怎样避免必须传递avname这个属性值?如果不传递就报错,这就需要使用isRequired关键字了,它表示必须进行传递,如果不传递就报错。

avname:PropTypes.string.isRequired

### 使用默认值defaultProps

有些人是非常腼腆的,他是不好意思选择的,所以有时候是需要有一个默认的人为她服务的。defalutProps就可以实现默认值的功能,比如现在把avname的默认值设置成"松岛枫" ,然后把avname的属性删除掉。

XiaojiejieItem.defaultProps = {
    avname:'松岛枫'
}

其实检测的类型非常多,你最好去官方文档看一下,能得到比较全面的了解。下面的课程有用到特殊的类型,还会继续给小伙伴们讲解。

第18节:React高级-ref的使用方法

在编写组件中的方法时,经常会遇到语义化很模糊的代码,这对于团队开发是一个很大的问题。因为review代码或者合作时都会影响开发效率。或者到这核心成员离开,项目倒闭的严重影响。所以我们必须重视react代码当中的语义化。ref是个不错的工具,快来学习一下吧。

代替原来的e.target.value

以前的案例中,我们写了下面的代码,使用了e.target,这并不直观,也不好看。这种情况我们可以使用ref来进行解决。

inputChange(e){
    
    this.setState({
        inputValue:e.target.value
    })
}

如果要使用ref来进行,需要现在JSX中进行绑定, 绑定时最好使用ES6语法中的箭头函数,这样可以简洁明了的绑定DOM元素。

<input 
    id="jspang" 
    className="input" 
    value={this.state.inputValue} 
    onChange={this.inputChange.bind(this)}
    //关键代码——----------start
    ref={(input)=>{this.input=input}}
    //关键代码------------end
    />

绑定后可以把上边的类改写成如下代码:

inputChange(){
    this.setState({
        inputValue:this.input.value
    })
}

这就使我们的代码变得语义化和优雅的多。但是就我个人的经验来讲,我是不建议用ref这样操作的,因为React的是数据驱动的,所以用ref会出现各种问题。

ref使用中的坑

比如现在我们要用ref绑定取得要服务的数量,可以先用ref进行绑定。

<ul ref={(ul)=>{this.ul=ul}}>
    {
        this.state.list.map((item,index)=>{
            return (
                <XiaojiejieItem 
                key={index+item}  
                content={item}
                index={index}
                deleteItem={this.deleteItem.bind(this)}
                />
            )
        })
    }
</ul>  

绑定后可以在addList()方法中,获取当前<div>的值.

 addList(){
    this.setState({
        list:[...this.state.list,this.state.inputValue],
        inputValue:''
    })
    //关键代码--------------start
    console.log(this.ul.querySelectorAll('div').length)
    //关键代码--------------end

}

这时候你打开控制台,点击添加服务按钮,你会返现数量怎么少一个?(就是这个坑),其实这个坑是因为React中更多setState是一个异步函数所造成的。也就是这个setState,代码执行是有一个时间的,如果你真的想了解清楚,你需要对什么是虚拟DOM有一个了解。简单的说,就是因为是异步,还没等虚拟Dom渲染,我们的console.log就已经执行了。

那这个代码怎么编写才会完全正常那,其实setState方法提供了一个回调函数,也就是它的第二个函数。下面这样写就可以实现我们想要的方法了。

addList(){
    this.setState({
        list:[...this.state.list,this.state.inputValue],
        inputValue:''
        //关键代码--------------start
    },()=>{
        console.log(this.ul.querySelectorAll('div').length)
    })
    //关键代码--------------end
}

现在到浏览器中查看代码,就完全正常了。这节课主要学习了ref的用法和ref中的坑。学完后练习一下吧,代码这东西,不练习你是学不会的。

第19节:React高级-生命周期讲解-1

React的生命周期是非常重要的知识点,所以关于React声明周期的课程可以多看几遍,我也会尽量的把React的生命周期讲的细致。生命周期的课程我分成三节来讲,这样更容易让你理解。

React生命周期图

React声明周期图

这张图看起来有点复杂,但是小伙伴们不要有恐慌心里,我会抽丝剥茧,给你详细讲解。

通过这张图你可以看到React声明周期的四个大阶段:

  1. Initialization:初始化阶段。
  2. Mounting: 挂在阶段。
  3. Updation: 更新阶段。
  4. Unmounting: 销毁阶段

什么是生命周期函数

如果非要用一句话把生命周期函数说明白,我觉的可以用这句话来说明:

生命周期函数指在某一个时刻组件会自动调用执行的函数

举例:写的小姐姐的例子。里边的render()函数,就是一个生命周期函数,它在state发生改变时自动执行。这就是一个标准的自动执行函数。

  • constructor不算生命周期函数。

constructor我们叫构造函数,它是ES6的基本语法。虽然它和生命周期函数的性质一样,但不能认为是生命周期函数。

但是你要心里把它当成一个生命周期函数,我个人把它看成React的Initialization阶段,定义属性(props)和状态(state)。

Mounting阶段

Mounting阶段叫挂载阶段,伴随着整个虚拟DOM的生成,它里边有三个小的生命周期函数,分别是:

  1. componentWillMount : 在组件即将被挂载到页面的时刻执行。
  2. render : 页面state或props发生变化时执行。
  3. componentDidMount : 组件挂载完成时被执行。

componentWillMount代码

componentWillMount(){
    console.log('componentWillMount----组件将要挂载到页面的时刻')
}

componentDidMount代码

componentDidMount(){
    console.log('componentDidMount----组件挂载完成的时刻执行')
}

render代码


render(){
    console.log('render---组件挂载中.......')
}

这时候我们查看一下控制台,会为我们打出如下提示:

componentWillMount----组件将要挂载到页面的时刻执行
render----开始挂载渲染
componentDidMount----组件挂载完成的时刻执行

这也是生命周期的顺序。有小伙伴会问我,这个函数书写有顺序吗?哪个在前?哪个在后?其实是没有顺序的,你可以随便改动他们的顺序。

注意的问题

componentWillMountcomponentDidMount这两个生命周期函数,只在页面刷新时执行一次,而render函数是只要有state和props变化就会执行,这个初学者一定要注意。

视频中会举例说明。

总结:这节课讲解了React的生命周期函数,先是简单了解了一下React生命周期函数的四大阶段,然后又详细学习了一下Mounting挂载阶段中的三个生命周期函数。下节课会学习Updation阶段的生命周期函数。

第20节:React高级-生命周期讲解-2

这节继续学习React生命周期中的Updation阶段,也就是组件发生改变的更新阶段,这是React生命周期中比较复杂的一部分,它有两个基本部分组成,一个是props属性改变,一个是state状态改变(这个在生命周期的图片中可以清楚的看到)。

shouldComponentUpdate函数

shouldComponentUpdate函数会在组件更新之前,自动被执行。比如写入下面的代码:

shouldComponentUpdate(){
    console.log('shouldComponentUpdate---组件发生改变前执行')
}

它要求返回一个布尔类型的结果,必须有返回值,这里就直接返回一个true了(真实开发中,这个是有大作用的)。

shouldComponentUpdate(){
    console.log('shouldComponentUpdate---组件发生改变前执行')
    return true
}

现在就可以在控制台console里看到结果了,并且结果是每次文本框发生改变时都会随着改变。如果你返回了false,这组件就不会进行更新了。 简单点说,就是返回true,就同意组件更新;返回false,就反对组件更新。

componentWillUpdate函数

componentWillUpdate在组件更新之前,但shouldComponenUpdate之后被执行。但是如果shouldComponentUpdate返回false,这个函数就不会被执行了。

//shouldComponentUpdate返回true才会被执行。
componentWillUpdate(){
    console.log('componentWillUpdate---组件更新前,shouldComponentUpdate函数之后执行')
}

componentDidUpdate

componentDidUpdate在组件更新之后执行,它是组件更新的最后一个环节。

componentDidUpdate(){
    console.log('componentDidUpdate----组件更新之后执行')
}

为了方便我们看出结果,可以在每个函数前加上序号。最后我们可以看到控制台输出的结果如下:

1-shouldComponentUpdate---组件发生改变前执行
2-componentWillUpdate---组件更新前,shouldComponentUpdate函数之后执行
3-render----开始挂载渲染
4-componentDidUpdate----组件更新之后执行

结果和我们写的顺序也是相对的,讲到这里,你一定对React的生命周期函数有了比较直观的了解了。

componentWillReceiveProps 函数

我们可以先在Xiaojiejie.js组件里写下这个函数,例如下面的代码。

componentWillReceiveProps(){
    console.log('componentWillReceiveProps')
}

这时候会发现函数什么时候都不会被执行,因为Xiaojiejie.js算是一个顶层组件,它并没接收任何的props。可以把这个函数移动到XiaojiejieItem.js组件中。

凡是组件都有生命周期函数,所以子组件也是有的,并且子组件接收了props,这时候函数就可以被执行了。

componentWillReceiveProps(){
        console.log('child - componentWillReceiveProps')
    }

这个时候再预览,就会看到componentWillReceiveProps执行了。那现在可以总结一下它的执行时间了。

子组件接收到父组件传递过来的参数,父组件render函数重新被执行,这个生命周期就会被执行。

  • 也就是说这个组件第一次存在于Dom中,函数是不会被执行的;
  • 如果已经存在于Dom中,函数才会被执行。

这个生命周期算是比较复杂的一个生命周期,需要我们花点时间去消化。

这节课就把updation里的生命周期函数都讲过了,下节课会把剩下的一点Unmounting讲了,然后会讲一下生命周期的实际应用。

第21节:React高级-生命周期讲解-3

其实这节课算是一个小的补充,把最后一个React的生命周期函数讲一下,这个生命周期周期函数就是componentWillUnmount,它是在组件去除时执行。

componentWillUnmount函数

这个函数时组件从页面中删除的时候执行,比如在XiaojiejieItem.js,写入下面的代码:

//当组件从页面中删除的时候执行
componentWillUnmount(){
    console.log('child - componentWillUnmount')
}

写完后,可以到浏览器终端中查看结果,当我们点击服务项,服务项被删除时,这个函数就被执行了。

总结:通过三节课的学习,我们已经把React的所有生命周期函数都讲完了,下节课会具体讲一下生命周期函数在实际开发中的应用。

第22节:React高级-生命周期改善程序性能

已经对React生命周期有了认识,那如何利用它提高组件的性能那?这节课我们会讲一个通过shouldComponentUpdate函数,改善React组件性能的例子。为了让这节课讲述的内容更加清晰,可以删除上几节课的生命周期函数。

小姐姐组件存在性能问题

是的,小姐姐组件已经写的很熟悉了,但是它有一个性能问题,我一直没告诉你,那就是子组件XiaojiejieItem频繁无用渲染render。如何能看出这个问题的那?

首先你要确认你安装了React Developer Tools 如果你没有安装,可以到前边的课程学习一下安装。有了这个浏览器插件,就可以在控制台中找到React标签,然后在右边点开设置,选中highlight Updates

这时候你在浏览器的文本框中输入一下内容,你可以清楚的看到子组件也发生了重新render的情况。

有很多程序员会忽略这样的性能损耗,认为没有什么大不了的,但是软件的卡顿是一点点产生的,所以必须要减少性能损耗。

可以在XiaojiejieItem.jsrender函数里加入下面的代码,更直观的看到这个问题。

render() { 
    console.log('child-render')
    return ( 
        <div onClick={this.handleClick}>
            {this.props.avname}为你做- {this.props.content}
        </div>
    );
}

利用shouldComponentUpdate解决

这个问题看似很小,但是当你页面很复杂时,足以影响用户体验,不要骗自己了。其实用shouldComponentUpdate函数就可以简单的解决调这个问题。

直接再XiaojiejieItem.js中加入下面的代码:

shouldComponentUpdate(){
    return false;
}

这时候在浏览器中查看,问题已经没有了。但是这样做太暴力了,否定了所有的东西,那如果在真实项目中,需要改变值属性值,达到渲染就没办法了。所以我们可以更优雅一下,写出下面的代码。

shouldComponentUpdate有两个参数:

  • nextProps:变化后的属性;
  • nextState:变化后的状态;
shouldComponentUpdate(nextProps,nextState){
    if(nextProps.content !== this.props.content){
        return true
    }else{
        return false
    }
   
}

现在的代码就优雅一些了,也不那么暴力了。这就算是完美解决了子组件的渲染性能问题,你写的代码质量也得到了提高。其实在面试React让写TODOList应用的,都是看这个来区分等级的,能写出来的,这算普通程序员;能写出来并作性能优化的,这算有经验的程序员。

第23节:React高级-axios数据请求

有了生命周期的知识,这节课学习远程数据请求的知识,小伙伴们肯定都知道,ajax可以远程请求,但是这写起来太麻烦了,我们用程序的ajax请求框架Axios来实现。

安装Axios

Axios的安装可以使用npm来进行安装,你可以直接在项目根目录下,输入下面的代码。

npm install -save axios

输入 后就可以正在的开始安装了。

npm install -save 和 -save-dev分不清

  • npm install xxx: 安装项目到项目目录下,不会将模块依赖写入devDependenciesdependencies

  • npm install -g xxx: -g的意思是将模块安装到全局,具体安装到磁盘哪个位置,要看 npm cinfig prefix的位置

  • npm install -save xxx-save的意思是将模块安装到项目目录下,并在package文件的dependencies节点写入依赖。

  • npm install -save-dev xxx-save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖。

作为一个前端,要清楚的知道npm install这四种用法,防止项目依赖错误,在别人下载你的代码没办法跑起来。

axios请求数据

安装好axiso之后,需要在使用ajax的地方先引入axios,比如现在想在Xiaojiejie.js中使用axios`,写入下面的代码进行引入:

import axios from 'axios'

引入后,可以在componentDidMount生命周期函数里请求ajax,我也建议在componentDidMount函数里执行,因为在render里执行,会出现很多问题,比如一直循环渲染;在componentWillMount里执行,在使用RN时,又会有冲突。所以强烈建议在componentDidMount函数里作ajax请求。

componentDidMount(){
    axios.post('https://web-api.juejin.im/v3/web/wbbr/bgeda')
        .then((res)=>{console.log('axios 获取数据成功:'+JSON.stringify(res))  })
        .catch((error)=>{console.log('axios 获取数据失败'+error)})
}

上面的代码是以掘金的一个接口为例,做了一次ajax请求。并且请求到了数据,给我们返回了。 总结:这节课学习了Axios的简单用法,并用最简单的方式,请求到了一个掘金网站的数据接口。ajax请求在你的项目中,会经常使用,也是我们读取和写入数据的一个桥梁,所以学习React的过程中,使用Axios作ajax请求非常重要,动手练习一下吧。

第24节:React高级-Axios请求EasyMock

上节课只是小试身手,用了一个掘金的临时接口,这个接口并不是自己写的,没准什么时候就不能使用了。在开发中都是前后端分离的,我们也需要自己模拟数据,通常把自己模拟数据这个过程就叫做mock,你可以用软件自己本地模拟数据,但是作为一个云注意者,我还是选择使用Easy-mock来模拟接口数据。

EasyMock新建一个接口

EasyMock网站:www.easy-mock.com/

然后你没注册需要注册一下,剩下的过程就看视频吧,因为这个都是些图形化的东西,我在视频中会详细讲解。

在创建接口时,写下如下代码:

{
  "data": ['基础按摩', '躺式采耳', '中药泡脚']
}

然后在上节课的Axios代码部分,把请求改为get,然后预览,到控制台查看结果。

componentDidMount(){
    axios.get('改为你自己的接口URL')
        .then((res)=>{console.log('axios 获取数据成功:'+JSON.stringify(res))  })
        .catch((error)=>{console.log('axios 获取数据失败'+error)})
}

这时候你应该可以获得接口数据了,也说明我们的接口制作正常了,这就很类似我们项目中的真实接口了。

修改程序 变为动态接口

在客户端已经得到了远程数据,那剩下的就是setState一下就可以了,代码如下:


componentDidMount(){
    axios.get('xxxx')
        .then((res)=>{
            console.log('axios 获取数据成功:'+JSON.stringify(res))
           
            this.setState({
                list:res.data.data
            })
          })
        .catch((error)=>{console.log('axios 获取数据失败'+error)})
}

那这时候再浏览React程序,也是完全可以使用的,不过已经不是以前写死的东西,而是使用远端接口数据。

总结:我们这两节课只是让你简单的学会React远程请求接口的方法,以后会用实战给大家讲解这部分知识,这里只要做到有个基本认识就可以了。

第25节:React高级-用CSS3实现react动画

前端的动画技术发展到现在,完全可以独立出一个岗位。我目前不属于动画岗,能力有限,也只是简单的给小伙伴们讲讲,做一些前端常用的效果。这节课先用我们最熟悉的CSS3在React中制作一个显示隐藏的动画特效,注意这是用CSS3实现的,其实React只做了业务逻辑。

新建一个Boss组件

其实这个组件你起什么名字都行,我也是临时想到的。

需要给“小姐姐服务菜单”增加一个Boss服务人物,点击一下按钮就会自动出现"Boss级人物-孙悟空",不要管什么恰当不恰当了,咱们是为了练习一下动画。在src文件夹下,新建一个Boss.js文件。然后用快速生成的方式生成基本结构:

在使用这些命令前,你要保证你安装了VSCode中的Simple React Snippets插件。

  • 先输入 imrc,然后回车,这是为了用import引入Reactcomponent
  • 再输入 ccc 然后回车,生成最基本的带constructor的代码结构。

就会生成下面的基本代码了(2秒钟完成下面的代码,这也是你工作中提高效率的关键):


import React, { Component } from 'react';
class Boss extends Component {
    constructor(props) {
        super(props);
        this.state = {  }
    }
    render() { 
        return (  );
    }
}
 
export default Boss;

然后我们先写一些JSX代码,让页面上有一段文字和一个按钮。代码如下:

import React, { Component } from 'react';
class Boss extends Component {
    constructor(props) {
        super(props);
        this.state = {  }
    }
    render() { 
        return ( 
            <div>
                <div>BOSS级人物-孙悟空</div>
                <div><button>召唤Boss</button></div>
            </div>
          );
    }
}
 
export default Boss;

编写业务逻辑

目前组件没有任何业务逻辑,只有一个UI,这是没办法实现动画效果的。业务逻辑是点击按钮的时候可以改变字的'

'显示隐藏。 要实现这个业务逻辑,先在constructor里增加state值isShow,详情请看下面的代码。

this.state = { 
    isShow:true
}

然后把“字”的'

'部分,增加className,并用isShow进行控制。

<div className={this.state.isShow ? 'show' : 'hide'}>BOSS级人物-孙悟空</div>

需要点击按钮时,有响应的事件,所以需要一个方法,我们编写一个toToggole()方法,代码如下:


toToggole(){
    this.setState({
        isShow:this.state.isShow ? false : true
    })
}

意思就是当isShowtrue时,我们赋值false;当isShowfalse时,我们赋值true`.

有了方法后,可以给<button>加上onClick响应事件了,代码如下:

<div><button onClick={this.toToggole}>召唤Boss</button></div>

写完这个事件,还是需要到constructor里绑定一下this。代码如下:

constructor(props) {
    super(props);
    this.state = { 
        isShow:true
    }
    this.toToggole = this.toToggole.bind(this);
}

这样我们的基本业务逻辑就算写完了,可以把代码加入到Xiaojiejie组件中,看一下效果了。

加入CSS动画

在页面上看不出任何的效果,如果你打开浏览器控制台是可以看到每次点击按钮,class都会变化的。界面没变化,知识我们没有写CSS。现在可以在style.css里写样式,代码如下:

.show{ opacity: 1; transition:all 1.5s ease-in;}
.hide{opacity: 0; transition:all 1.5s ease-in;}

这样就用CSS3实现了React中动画,这知识最简单的实践动画,所以先不要吐槽,接下来几节课我们会继续讲解React中动画的知识。继续跟着技术胖一起学习吧。

第26节:React高级-CSS3的keyframes动画

transition只能作一些最简单的动画,如果你想稍微复杂点,transition就做不出来了。这时候就可以用CSS3中的关键帧动画keyframes。这节课就花几分钟学习一下keyframes,如果你CSS3动画不能分的知识很好,完全可以跳过这节课。

keyframes动画介绍

此属性与animation属性是密切相关的,keyframes译成中文就是关键帧,我最早接触这个关键帧的概念是字flash中,现在Flash已经退出历史舞台了。他和transition比的优势是它可以更加细化的定义动画效果。比如我们设置上节课的按钮隐藏动画,不仅可以设置透明度,还可以设置颜色。

@keyframes hide-item{
    0% {
        opacity:1;
        color:yellow;
    }
    50%{
        opacity: 0.5 ;
        color:red;
    }
    100%{
        opacity:0;
        color: green;
    }
}

这就算是你的动画制作好了,但是动画还没有使用。

使用动画

使用动画的关键词是animation,然后后边跟上你的制作的动画名称,如下面这段代码。

.hide{ animation:hide-item 2s ease-in ; }

这句的意思就是,使用hide-item动画,持续时间是2秒钟,然后缓动效果是由慢到快(开始的时候慢,之后快)。

但是你会发现,动画执行一遍后又恢复了原状,这个是因为没设置forwards属性,它是用来控制停止到最后一帧的。 我们把代码改写成下面的样子。

.hide{ animation:hide-item 2s ease-in forwards; }

完整代码的实现

keyframes的动画已经基本学会了,接下来就把所有的代码修改为keyframes的形式吧。所有代码如下:

.show{ animation:show-item 2s ease-in forwards; }
.hide{ animation:hide-item 2s ease-in forwards; }

@keyframes hide-item{
    0% {
        opacity:1;
        color:yellow;
    }
    50%{
        opacity: 0.5 ;
        color:red;
    }
    100%{
        opacity:0;
        color: green;
    }
}

@keyframes show-item{
    0% {
        opacity:0;
        color:yellow;
    }
    50%{
        opacity: 0.5 ;
        color:red;
    }
    100%{
        opacity:1;
        color: green;
    }
}

总结:keyframes也是只能实现很简单的动画效果,一些复杂的动画最好还是使用别人造好的轮子,下节课继续学习React中的动画吧。

第27节:React高级-react-transition-group

React有着极好的开发生态,开发需要的任何基本需求都可以找到官方或大神造的轮子,动画这种必不可少的东西当然也不例外,React生态中有很多第三方的动画组件,你应该学习一下react-transition-group动画组件。目前我在工作中使用表现很好,可以满足日常动画开发需求。

推荐的最重要理由是:这个也是react官方提供的动画过渡库,有着完善的API文档(完善到我都不好意思再讲一遍)。

安装react-transition-group

使用它要先进行安装,这里使用npm的形式进行安装了,当然也可以使用yarn

先用VSCode打开项目根目录,然后打开终端,输入下面的命令,进行安装:

npm install react-transition-group --save

安装好后,你可以先去github上来看一下文档,他是有着三个核心库(或者叫组件)。

  • Transition
  • CSSTransition
  • TransitionGroup

### 使用CSSTransition

其实这个库用起来根ng-animate差不多,先来看看如何使用CSSTransition

先用import进行引入,代码如下:

import { CSSTransition } from 'react-transition-group'

引入后便可以使用了,使用的方法就和使用自定义组件一样,直接写<CSSTransition>,而且不再需要管理className了,这部分由CSSTransition进行管理。修改上节课写的Boss.js文件里的render区域。

render() { 
    return ( 
        <div>
            <CSSTransition 
                in={this.state.isShow}   //用于判断是否出现的状态
                timeout={2000}           //动画持续时间
                classNames="boss-text"   //className值,防止重复
            >
                <div>BOSS级人物-孙悟空</div>
            </CSSTransition>
            <div><button onClick={this.toToggole}>召唤Boss</button></div>
        </div>
        );
}

需要注意的是classNames这个属性是由s的,如果你忘记写,会和原来的ClassName混淆出错,这个一定要注意。

我们把上节课的代码进行了改造,然后你就可以到CSS中改写style了。在修改样式之前,有那些类名。

  • xxx-enter: 进入(入场)前的CSS样式;
  • xxx-enter-active:进入动画直到完成时之前的CSS样式;
  • xxx-enter-done:进入完成时的CSS样式;
  • xxx-exit:退出(出场)前的CSS样式;
  • xxx-exit-active:退出动画知道完成时之前的的CSS样式。
  • xxx-exit-done:退出完成时的CSS样式。

知道了这些要设置的CSS,就可以删除原来写的CSS了,把下面的代码写上:

.input {border:3px solid #ae7000}

.boss-text-enter{
    opacity: 0;
}
.boss-text-enter-active{
    opacity: 1;
    transition: opacity 2000ms;

}
.boss-text-enter-done{
    opacity: 1;
}
.boss-text-exit{
    opacity: 1;
}
.boss-text-exit-active{
    opacity: 0;
    transition: opacity 2000ms;

}
.boss-text-exit-done{
    opacity: 0;
}

这时候你的动画样式就正常了,你回发现我们再也不用自己管理className了,而是完全交给了react-transition-group来作。

unmountOnExit 属性

学到这里,会感觉这样写也没有简化多少,更没特殊的效果,技术胖你又玩我。

其实不是的,比如我们给<CSSTransition>加上unmountOnExit,加上这个的意思是在元素退场时,自动把DOM也删除,这是以前用CSS动画没办法做到的。

比如我们把代码写成这个样子:

render() { 
    return ( 
        <div>
            <CSSTransition 
                in={this.state.isShow}   //用于判断是否出现的状态
                timeout={2000}           //动画持续时间
                classNames="boss-text"   //className值,防止重复
                unmountOnExit
            >
                <div>BOSS级人物-孙悟空</div>
            </CSSTransition>
            <div><button onClick={this.toToggole}>召唤Boss</button></div>
        </div>
        );
}

总结:这几课简单的学习了一下React官方的react-transition-group动画库,也实现了一些动画效果。下节课继续学习动画库中的钩子函数和transition-group

第28节:React高级-多DOM动画制作和编写

通过上一节的学习,只能控制一个DOM元素的动画,想控制多个动画react-transition-group这个动画库也是可以做到的。这节课就带你了解一下多DOM动画控制的方法。

使用TransitionGroup

它就是负责多个DOM元素的动画的,我们还是拿小姐姐这个案例作例子,现在可以添加任何的服务项目,但是都是直接出现的,没有任何动画,现在就给它添加上动画。添加动画,先引入transitionGrop

直接打开/src/Xiaojiejie.js的文件,然后在最顶部同时

import {CSSTransition , TransitionGroup} from 'react-transition-group'

引入之后,就可以使用这个组件了,方法是在外层增加<TransitionGroup>标签。

<ul ref={(ul)=>{this.ul=ul}}>
    <TransitionGroup>
    {
        this.state.list.map((item,index)=>{
            return (
                <XiaojiejieItem 
                key={index+item}  
                content={item}
                index={index}
                deleteItem={this.deleteItem.bind(this)}
                />
            )
        })
    }
    </TransitionGroup>
</ul> 

这个需要放在循环的外边,这样才能形成一个组动画,但是只有这个<TransitonGroup>是不够的,你还是需要加入<CSSTransition>,来定义动画。

加入<CSSTranstion>标签

可以完全仿照上节课的经验,为Xiaojiejie组件,加上具体的动画设置,就可以实现多DOM元素的动画效果了。代码如下:

<ul ref={(ul)=>{this.ul=ul}}>
    <TransitionGroup>
    {
        this.state.list.map((item,index)=>{
            return (
                <CSSTransition
                    timeout={1000}
                    classNames='boss-text'
                    unmountOnExit
                    appear={true}
                    key={index+item}  
                >
                    <XiaojiejieItem 
                    content={item}
                    index={index}
                    deleteItem={this.deleteItem.bind(this)}
                    />
                </CSSTransition>
            )
        })
    }
    </TransitionGroup>
</ul>  
<Boss />
</Fragment>

总结:React动画还有很多知识,能做出很多酷炫的效果,完全可以单独分出来一个岗位,我在工作中用的都是比较简单的动画,用react-transition-group动画已经完全可以满足我的日常开发需求了。如果你想学习更多的React动画知识,可以看看文档或者书。

学完这节,React的基础知识部分就到这里了,下节课开始讲解Rudex的知识,希望你能跟着技术胖继续学习,一起努力进步。

技术胖315集视频镇楼

1-React(新版)基础免费视频教程

  1. React课程前言(315)

  2. React简介和Vue对比(314)

  3. React开发环境搭建(313)

  4. 脚手架生成的项目目录介绍 (312)

  5. HelloWorld和组件的讲解 (311)

  6. React中JSX语法简介 (310)

  7. React实例-小姐姐服务菜单 (309)

  8. React实例-宝剑磨的好,理论不能少(308)

  9. React实例-老板我要加个钟(307)

  10. React实例-宝剑虽然好 老腰受不了(306)

  11. React进阶-JSX防踩坑的几个地方(305)

  12. React进阶-Simple React Snippets(304)

  13. React进阶-组件的拆分(303)

  14. React进阶-父子组件的传值(303)

  15. React进阶-单项数据流和其他(302)

  16. React高级-调试工具的安装及使用(301)

  17. React高级-PropTypes校验传递值(300)

  18. React高级-ref的使用方法(299)

  19. React高级-生命周期讲解-1(298)

  20. React高级-生命周期讲解-2(297)

  21. React高级-生命周期讲解-3(296)

  22. React高级-生命周期改善程序性能(295)

  23. React高级-axios数据请求(294)

  24. React高级-Axios请求EasyMock(293)

  25. React高级-用CSS3实现react动画(292)

  26. React高级-CSS3的keyframes动画(291)\

  27. React高级-react-transition-group(290)

  28. React高级-多DOM动画制作和编写(289)

2-Flutter基础视频教程

  1. 认识一下Flutter(288)

  2. Flutter开发环境搭建Windows版(287)

  3. Flutter开发环境搭建Mac版(286)

  4. 安装AVD虚拟机 Flutter跑起来(285)

  5. VSCode下如何玩转Flutter(284)

  6. 写一个HelloWorld程序(283)

  7. Text Widget 文本组件的使用(282)

  8. Container容器组件的使用1(281)

  9. Container容器组件的使用2(280)

  10. Image图片组件的使用(279)

  11. ListView 列表组件简介(278)

  12. ListView 横向列表的使用(277)

  13. ListView 动态列表的使用(276)

  14. GridView网格列表组件(275)

  15. Flutter-水平布局Row的使用(274)

  16. Flutter-垂直布局Column组件(273)

  17. Flutter-Stack层叠布局(272)

  18. Stack的Positioned属性(271)

  19. 卡片组件布局(270)

  20. 一般页面导航和返回(269)

  21. 导航参数的传递和接收(1)(268)

  22. 导航参数的传递和接收(2)(267)

  23. 页面跳转并返回数据(266)

  24. 静态资源和项目图片的处理(265)

  25. Flutter客户端打包(264)

3-Flutter 20课小实例练习

  1. 底部导航栏制作-1(263)

  2. 底部导航栏制作-2(262)

  3. 不规则底部工具栏制作-1(261)

  4. 不规则底部工具栏制作-2(260)

  5. 酷炫的路由动画-1(259)

  6. 酷炫的路由动画-2(258)

  7. 毛玻璃效果制作(257)

  8. 保持页面状态(256)

  9. 保持页面状态-2(255)

  10. 一个不简单的搜索条-1(254)

  11. 一个不简单的搜索条-2(253)

  12. 流式布局 模拟添加照片效果(252)

  13. 展开闭合案例(251)

  14. 展开闭合列表案例(250)

  15. 贝塞尔曲线切割(249)

  16. 波浪形式的贝塞尔曲线(248)

  17. 打开应用的闪屏动画案例(247)

  18. 右滑返回上一页案例(246)

  19. ToolTip控件实例(245)

  20. Draggable控件实例(244)

4-ES6免费视频教程(18集)

  1. ES6的开发环境搭建(243)

  2. 新的声明方式(242)

  3. 变量的解构赋值(241)

  4. 扩展运算符和rest运算符(240)

  5. 字符串模版(239)

  6. ES6数字操作(238)

  7. ES6中新增的数组知识(1)(237)

  8. ES6中新增的数组知识(2)(236)

  9. ES6中的箭头函数和扩展(235)

  10. ES6中的函数和数组补漏(234)

  11. ES6中对象(233)

  12. Symbol在对象中的作用(232)

  13. Set和WeakSet数据结构(231)

  14. map数据结构(230)

  15. 用Proxy进行预处理(229)

  16. promise对象的使用(228)

  17. class类的使用(227)

  18. 模块化操作(226)

5-前端必会的 Nginx免费教程 (共11集)

  1. 初识Nginx和环境准备(225)

  2. Nginx的快速搭建(224)

  3. Nginx基本配置文件详讲(223)

  4. Nginx服务启动、停止、重启(222)

  5. 自定义错误页和访问设置(221)

  6. Nginx访问权限详讲(220)

  7. Nginx设置虚拟主机(219)

  8. Nginx使用域名设置虚拟主机(218)

  9. Nginx反向代理的设置(217)

  10. Nginx适配PC或移动设备(216)

  11. Nginx的Gzip压缩配置(215)

6-TypeScript免费视频教程 ,Deno前置知识 (共15集)

  1. 初识TypeScript(214)

  2. 开发环境的安装(213)

  3. 变量类型的那些事(212)

  4. TypeScript的函数(211)

  5. 三种函数的定义方式(210)

  6. 函数中变量的作用域(209)

  7. 引用类型-数组(208)

  8. 引用类型-字符串啊(207)

  9. 引用类型-日期对象(206)

  10. 引用类型-正则表达式(205)

  11. 面向对象编程-类的声明和使用(204)

  12. 面向对象编程-修饰符(203)

  13. 面向对象编程-继承和重写(202)

  14. 面向对象编程-接口(201)

  15. 面向对象编程-命名空间(200)

7-Nuxt.js免费视频教程 开启SSR渲染 ( 共11集)

  1. NuxtJS课程介绍(199)

  2. Nuxt环境搭建和Hello World(198)

  3. Nuxt常用配置项(197)

  4. Nuxt的路由配置和参数传递(196)

  5. Nuxt的动态路由和参数校验(195)

  6. Nuxt的路由动画效果(194)

  7. Nuxt的默认模版和默认布局(193)

  8. Nuxt的错误页面和个性meta设置(192)

  9. asyncData方法获取数据(191)

  10. 静态资源和打包(190)

8-CocosCreator 从基础到实战免费视频

  1. CocosCreator简介和HelloWorld(189)

  2. 软件界面介绍和跳动的小球(188)

  3. Scene介绍和基本操作(187)

  4. 玩家输入事件监听(186)

  5. Prefab和计时器(185)

  6. 实战-游戏简介和项目分析(184)

  7. 实战-UI界面布局(183)

  8. 实战-主角的动作监听和跳动(182)

  9. 实战-随机生成地刺(181)

  10. 实战-点击生成地刺和移动(180)

  11. 实战-碰撞检测(179)

  12. 实战-倒计时和分数增加(178)

  13. 实战-欢迎界面代码编写(177)

  14. 实战-添加音效(176)

  15. 实战-发布游戏(175)

9-挑战全栈 MongoDB基础视频教程 (共21集)

  1. 认识和安装MongoDB(174)

  2. Mongo基本命令-1(173)

  3. Mongo基本命令-2(172)

  4. 用js文件写mongo命令(171)

  5. 批量插入的正确方法(170)

  6. 修改:Update常见错误(169)

  7. 修改:初识update修改器(168)

  8. 修改:update数组修改器(167)

  9. 修改:状态返回与安全(166)

  10. 查询:find的不等修饰符(165)

  11. 查询:find的多条件查询(164)

  12. 查询:find的数组查询(163)

  13. 查询:find的参数使用方法(162)

  14. 查询:find如何在js文本中使用(161)

  15. 索引:构造百万级数据(160)

  16. 索引:索引入门(159)

  17. 索引:复合索引(158)

  18. 索引:全文索引(157)

  19. 管理:用户的创建、删除与修改(156)

  20. 管理:备份和还原(155)

  21. 管理:图形界面管理(完结)(154)

10-挑战全栈 Koa2免费视频教程 (共13集)

  1. Koa开发环境搭建(153)

  2. async/await的使用方法(152)

  3. Get请求的接收(151)

  4. POST请求如何接收(1)(150)

  5. POST请求如何接收(2)(149)

  6. koa-bodyparser中间件(148)

  7. Koa2原生路由实现(147)

  8. Koa-router中间件(1)入门(146)

  9. Koa-router中间件(2)层级(145)

  10. Koa-router中间件(3)参数(144)

  11. Koa2中使用cookie(143)

  12. Koa2的模板初识(ejs)(142)

  13. koa-static静态资源中间件(141)

11-React免费视频教程-入门和组件 (共11集)

  1. React课程介绍(140)

  2. 环境搭建和HelloWorld程序(139)

  3. 初识JSX语法(138)

  4. 进阶JSX语法(137)

  5. React组件:state成员(136)

  6. React组件:props和render成员(135)

  7. React组件:生命周期(134)

  8. React组件小实例-必做练习(133)

  9. React组件:this.props.children(132)

  10. React组件:props属性验证(131)

  11. React组件:获取真实DOM节点(130)

12-React免费视频教程-表单的应用 (共4集)

  1. 表单的事件响应和bind复用(129)

  2. React表单name复用(128)

  3. React表单-可控组件(127)

  4. React表单-不可控组件(126)

13-React项目构建和路由 免费视频教程 (共10集)

  1. 构建:create-react-app 快速脚手架(125)

  2. 构建:generator-react-webpack(124)

  3. 构建:webpack一步一步构建01(123)

  4. 构建:webpack一步一步构建02(122)

  5. 路由:Hello React路由(121)

  6. 路由:NavLink中常用选项(120)

  7. 路由:404设置和跳转设置(119)

  8. 路由:通过路由传值的方法(118)

  9. 路由:Router中的属性和路由模式(117)

  10. 路由:prompt用法讲解(116)

14-Vue2.0视频教程-内部指令(共8集)

  1. 走起我的Vue2.0(115)

  2. v-if v-else v-show 指令(114)

  3. v-for指令 :解决模板循环问题(113)

  4. v-text & v-html(112)

  5. v-on:绑定事件监听器(111)

  6. v-model指令(110)

  7. v-bind 指令(109)

  8. 其他内部指令(v-pre & v-cloak & v-once)(108)

15-【第二季】Vue2.0视频教程-全局API(共9集)

  1. Vue.directive 自定义指令(107)

  2. Vue.extend构造器的延伸(106)

  3. Vue.set全局操作(105)

  4. Vue的生命周期(钩子函数)(104)

  5. Template 制作模版(103)

  6. Component 初识组件(102)

  7. Component 组件props 属性设置(101)

  8. Component 父子组件关系(100)

  9. Component 标签(099)

16-【第三季】Vue2.0视频教程-选项(共6集)

  1. propsData Option 全局扩展的数据传递(098)

  2. computed Option 计算选项(097)

  3. Methods Option 方法选项(096)

  4. Watch 选项 监控数据(095)

  5. Extends Option 扩展选项(094)


17-【第四季】Vue2.0视频教程-实例和内置组件(共4集)

  1. 实例入门-实例属性(093)

  2. 实例方法(092)

  3. 实例事件(091)

  4. 内置组件 -slot讲解(090)

18-Vue-cli 免费视频教程(共3集)

  1. Vue-cli,开始吧骚年(089)

  2. Vue-cli项目结构讲解(088)

  3. 解读Vue-cli的模板(087)

19-Vue-router免费视频教程(共11集)

  1. Vue-router入门(086)

  2. vue-router配置子路由(085)

  3. vue-router如何参数传递(084)

  4. 单页面多路由区域操作(083)

  5. vue-router 利用url传递参数(082)

  6. vue-router 的重定向-redirect(081)

  7. alias别名的使用(080)

  8. 路由的过渡动画(079)

  9. mode的设置和404页面的处理(078)

  10. 路由中的钩子(077)

  11. 编程式导航(076)

20-vuex免费视频教程(共6集)

  1. 初出茅庐 来个小Demo(075)

  2. state访问状态对象(074)

  3. Mutations修改状态(073)

  4. getters计算过滤操作(072)

  5. actions异步修改状态(071)

  6. module模块组(070)

21- Vue实战视频-快餐店收银系统 (共11集)

  1. Mockplus把我们的想法画出来(069)

  2. Vue-cli搭建开发环境(068)

  3. 搞定项目图标Iconfont(067)

  4. 编写独立的侧边栏导航组件(066)

  5. 开启Element封印(065)

  6. 利用Element快速布局(1)(064)

  7. 利用Element快速布局(2)(063)

  8. Axios从远程读取数据(062)

  9. 订单模块制作 核心功能-1(061)

  10. 订单模块制作 核心功能-2(060)

  11. 项目打包和上线(059)

22-WEEX免费视频教程-从入门到放肆 (共17集)

  1. 课程介绍(058)

  2. 开发环境安装(1)(057)

  3. 开发环境安装(2)(056)

  4. weex常用命令和热更新(055)

  5. Android Studio 开发设置

  6. weex和vue的爱恨情仇(054)

  7. 自定义组件和Text组件

  8. Input组件和初识内建模块(053)

  9. Image和video组件(052)

  10. 一起作个列表出来(051)

  11. 从后端服务器上获取数据(050)

  12. 作轮播图片效果(049)

  13. a组件和web组件(048)

  14. 通用事件和动画(047)

  15. 教会你自学weex(046)

  16. Navigator和webview模块(046)

  17. vue-router的使用(045)

23-Fabric.js 免费视频教程(共13集)

  1. 初识简单而且强大的Fabric.js库(044)

  2. 在Canvas上画简单的图形(043)

  3. 在Canvas上插入图片并设置旋转属性(042)

  4. Fabric.js用路径画不规则图形(041)

  5. Fabric.js的动画设置(040)

  6. Fabric.js的图像过滤器(039)

  7. Fabric.js的颜色模式和相互转换(038)

  8. Fabric.js的渐变填充(037)

  9. Fabric.js的文本设置(036)

  10. Fabric.js的事件系统(035)

  11. Fabric.js的分组绘制(一)(034)

  12. Fabric.js的分组绘制(二)(033)

  13. Fabric.js的序列化和反序列化(032)

24-CSS3免费视频教程(共31集)

  1. 嫁汉嫁汉穿衣吃饭(031)

  2. CSS3新特性简介和浏览器支持情况 (030)

  3. CSS3伪类选择器1(029)

  4. CSS3伪类选择器2结构伪类选择器(028)

  5. CSS3伪元素(027)

  6. CSS3用border-radius画圆形(026)

  7. CSS3画三角形和对话框(025)

  8. CSS3画菱形和平行四边形(024)

  9. 画五角星和六角星(023)

  10. CSS3 画五角星和六角星(022)

  11. CSS3画心形和蛋形(021)

  12. CSS3画太极阴阳图(020)

  13. CSS3制作透明背景层(019)

  14. CSS3的颜色模式(1)(018)

  15. CSS3的颜色模式(2)-实例仿天猫商品展示效果(017)

  16. CSS3线性渐变(016)

  17. CSS3径向渐变 radial-gradient(015)

  18. CSS3重复性渐变(014)

  19. CSS3盒子阴影效果box-shadow(013)

  20. CSS3制作缓慢变长的方形(transition特效)(012)

  21. CSS3制作缓慢变长的方形(transition特效)(011)

  22. CSS3过渡的timing-function属性详解(010)

  23. CSS3仿天猫专题过渡效果实例(009)

  24. SS3仿天猫类别过渡效果制作(008)

  25. CSS3动画中的@keyframes关键帧讲解(007)

  26. CSS3动画animation复合属性讲解(006)

  27. CSS3动画综合实例制作-内容加载loading动画实现(005)

  28. CSS3 Loading动画效果实例2(004)

  29. CSS3制作发光字,立体字,苹果字体(003)

  30. CSS3 用text-overflow解决文字排版问题(002)

  31. CSS3 新的字体单位rem-大结局(001)

还在不断录制中................