目标:已录制 315 集免费视频,目标 1000 集免费视频。 [视频目录(315/1000)]

React免费视频教程

这是一门免费课程,会详细讲解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的官方网站为:https://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中文网址:http://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网站:https://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的知识,希望你能跟着技术胖继续学习,一起努力进步。