# React 16.x
# React简介
ReactJS是由Facebook在2013年5月推出的一款JS前端开源框架,推出式主打特点式函数式编程风格。
React优点总结
生态强大:现在没有哪个框架比React的生态体系好的,几乎所有开发需求都有成熟的解决方案。
上手简单: 你甚至可以在几个小时内就可以上手React技术,但是他的知识很广,你可能需要更多的时间来完全驾驭它。
社区强大:你可以很容易的找到志同道合的人一起学习,因为使用它的人真的是太多了。
React三大体系

# React开发环境搭建
安装Node.js
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
脚手架的安装
创建第一个React项目
脚手架安装好以后,就可以创建项目了,我们在D盘创建一个ReactDemo文件夹,然后进入这个文件夹,创建新的React项目。
D: //进入D盘
mkdir ReactDemo //创建ReactDemo文件夹
create-react-app demo01 //用脚手架创建React项目
cd demo01 //等创建完成后,进入项目目录
npm start //预览项目,如果能正常打开,说明项目创建成功
# 脚手架生成的项目目录介绍
项目根目录中的文件
先从进入项目根目录说起,也就是第一眼看到的文件(版本不同,可能稍有不同)
● 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必须用到这个文件,有了这个文件,就相当于有了离线浏览的功能。 此时,可以通过npm start将项目运行起来,默认端口为3000
# HelloWorld和组件的讲解
** 入口文件的编写**
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />,document.getElementById('root'))
App组件编写
import React, {Component} from 'react';
// 这行代码相当于下面两行
// import React from 'react'
// const Component = React.Component
class App extends Component{
render(){
return (
<div>
Hello JSPang
</div>
)
}
}
export default App;
# React中JSX语法简介
JSX简介
JSX就是Javascript和XML结合的一种格式。React发明了JSX,可以方便的利用HTML语法来创建虚拟DOM,当遇到<,JSX就当作HTML解析,遇到{就当JavaScript解析.
组件和普通JSX语法区别
自定义的组件必须首写字母要进行大写,而JSX是小写字母开头的。
JSX中使用三元运算符
import React from 'react'
const Component = React.Component
class App extends Component{
render(){
return (
<ul className="my-list">
<li>{false?'语文':'数学'}</li>
<li>I love React</li>
</ul>
)
}
}
export default App;
注意
组件外层包裹原则:React要求必须在一个组件的最外层进行包裹。
Fragment标签讲解
加上最外层的DIV,组件就是完全正常的,但是你的布局就偏不需要这个最外层的标签怎么办?比如我们在作Flex布局的时候,外层还真的不能有包裹元素。这种矛盾其实React16已经有所考虑了,为我们准备了Fragment标签。
要想使用Fragment,需要先进行引入。
import React,{Component,Fragment } from 'react';
然后把最外层的div标签,换成Fragment标签,代码如下。
import React, {Component,Fragment } from 'react';
class Example extends Component{
render(){
return (
<Fragment>
<div><input /> <button> 增加课程 </button></div>
<ul>
<li>数学</li>
<li>语文</li>
</ul>
</Fragment>
)
}
}
export default Example ;
这时候你再去浏览器的Elements中查看,就回发现已经没有外层的包裹了。
# React-响应式设计
react不建议你直接操作DOM元素,而是要通过数据进行驱动,改变界面中的效果。React会根据数据的变化,自动的帮助你完成界面的改变。所以在写React代码时,你无需关注DOM相关的操作,只需要关注数据的操作就可以了(这也是React如此受欢迎的主要原因,大大加快了我们的开发速度)。
//js的构造函数,由于其他任何函数执行
constructor(props){
super(props) //调用父类的构造函数,固定写法
this.state={
inputValue:'' , // input中的值
list:[] //服务列表
}
}
# JSX踩坑之路
JSX代码注释
<Fragment>
{/* 正确注释的写法 */}
<div>
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>
</Fragment>
JSX中的class陷阱
要求把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标签的坑
react中,如果label标签中使用for,你会发现浏览效果虽然可以正常,但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>
# React进阶-Simple React Snippets
安装Simple React Snippets,可以实现快速输入react基础代码。
打开VSCode的插件查单,然后在输入框中输入Simple React Snippets,然后点击进行安装就可以了。
# React进阶-父子组件的传值
父组件
import React, { Component } from 'react';
import Children from '../../component/Children';
class Parent extends Component {
constructor(props){
super(props);
this.state={
data: []
}
}
onSubmit = (value) => {
console.log(value); // value即为子组件传递过来的参数
}
render() {
return (
<div>
<Children
listData={this.state.data} // 父组件向子组件传值
onSubmit={this.onSubmit} // 父组件向子组件传方法
/>
</div>
)
}
}
export default Parent;
子组件
import React, { Component } from 'react';
class Children extends Component {
constructor(props){
super(props);
this.state={
list: [],
device: ''
}
}
componentDidMount () {
this.setState({
list: this.props.listData // listData为父组件传过来的数据
})
}
childFunc = () => {
this.props.onSubmit(this.state.device); // 子组件调用父组件方法,并将值传递给父组件
}
render() {
return (
<div>
<div onClick={this.childFunc}></div>
</div>
)
}
}
export default Children;
注:传值可以通过父子组件之间进行传值(主要是利用 props 来进行交流,父组件用this.state传值,子组件用this.prop),也可以通过父组件将值存于models中,然后子组件在props中获取。
# React进阶-单项数据流
通过父组件与子组件中可以看出,父组件往子组件传的值是不允许修改的,只能显示。
函数式编程
在面试React时,经常会问道的一个问题是:函数式编程的好处是什么?
● 函数式编程让我们的代码更清晰,每个功能都是一个函数。 ● 函数式编程为我们的代码测试代理了极大的方便,更容易实现前端自动化测试。
React框架也是函数式编程,所以说优势在大型多人开发的项目中会更加明显,让配合和交流都得心应手。
# React高级-调试工具的安装及使用
下载React developer tools
这个需要在chrome浏览器里进行,并且需要科学上网(这东西我不能在这里教,所以自行百度吧)。
点击浏览器地址栏最右边的...,然后选择更多工具,然后选择扩展程序。
点击打开chrome网上应用店,直接在搜索框里搜索React,出现的第一个就是。
点击添加至Chrome,然后就是等待了..........
React developer tools的三种状态
React developer tools有三种颜色,三种颜色代表三种状态:
● 灰色: 这种就是不可以使用,说明页面不是又React编写的。 ● 黑色: 说明页面是用React编写的,并且处于生成环境当中。 ● 红色: 说明页面是用React编写的,并且处于调试环境当中。
React developer tools使用
打开浏览器,然后按F12,打开开发者工具,然后在面板的最后一个,你会返现一个React,这个就是安装的插件了。
在这里你可以清晰的看到React的结构,让自己写的代码更加清晰,你还可以看到组间距的数据传递,再也不用写console.log来测试程序了。
注意
在科学上网前提下。
# React高级-PropTypes校验传递值
在父组件向子组件传递数据时,使用了属性的方式,也就是props,但“小姐姐服务菜单”的案例并没有任何的限制。这在工作中时完全不允许的,因为大型项目,如果你不校验,后期会变的异常混乱,业务逻辑也没办法保证。
PropTypes的简单应用
我们在往子组件里传递了4个值,有字符串,有数字,有方法,这些都是可以使用PropTypes限制的。在使用需要先引入PropTypes。
import PropTypes from 'prop-types';
引入后,就可以在组件的下方进行引用了,需要注意的是子组件的最下面(不是类里边),写入下面的代码:
Example.propTypes={
content:PropTypes.string,
deleteItem:PropTypes.func,
index:PropTypes.number
}
给出完成代码,如下:
import React from 'react';
import PropTypes from 'prop-types';
class Children extends React.Component{
constructor(props) {
super(props);
this.state = {
}
}
getItem(index) {
this.props.deleteItem(index);
}
render() {
return (<li onClick={this.getItem.bind(this, this.props.index)}>{this.props.content}</li>)
}
}
export default Children;
Children.propTypes = {
index: PropTypes.number.isRequired, // isRequired为必传,具体请查看官网
content: PropTypes.string,
deleteItem: PropTypes.func
}
Children.defaultProps = { // 为设置props的初始值
name: '小杨'
}
使用默认值defaultProps
如上面代码所示,可以通过defaultProps设置props的初始值。
# React高级-ref的使用方法
# React高级-生命周期讲解-1
React生命周期图
通过这张图你可以看到React声明周期的四个大阶段:
- Initialization:初始化阶段。
- Mounting: 挂在阶段。
- Updation: 更新阶段。
- Unmounting: 销毁阶段
什么是生命周期函数
如果非要用一句话把生命周期函数说明白,我觉的可以用这句话来说明:
生命周期函数指在某一个时刻组件会自动调用执行的函数
举例:js文件里边的render()函数,就是一个生命周期函数,它在state发生改变时自动执行。这就是一个标准的自动执行函数。
constructor不算生命周期函数。
constructor我们叫构造函数,它是ES6的基本语法。虽然它和生命周期函数的性质一样,但不能认为是生命周期函数。
但是你要心里把它当成一个生命周期函数,我个人把它看成React的Initialization阶段,定义属性(props)和状态(state)。
1.Mounting阶段
Mounting阶段叫挂载阶段,伴随着整个虚拟DOM的生成,它里边有三个小的生命周期函数,分别是:
- componentWillMount : 在组件即将被挂载到页面的时刻执行。
- render : 页面state或props发生变化时执行。
- componentDidMount : 组件挂载完成时被执行。
componentWillMount代码
componentWillMount(){
console.log('componentWillMount----组件将要挂载到页面的时刻')
}
componentDidMount代码
componentDidMount(){
console.log('componentDidMount----组件挂载完成的时刻执行')
}
render代码
render(){
console.log('render---组件挂载中.......')
}
这时候我们查看一下控制台,会为我们打出如下提示:
componentWillMount----组件将要挂载到页面的时刻执行
render----开始挂载渲染
componentDidMount----组件挂载完成的时刻执行
这也是生命周期的顺序。
注意
componentWillMount和componentDidMount这两个生命周期函数,只在页面刷新时执行一次,而render函数是只要有state和props变化就会执行。
2.Updation
eact生命周期中的Updation阶段,也就是组件发生改变的更新阶段,这是React生命周期中比较复杂的一部分,它有两个基本部分组成,一个是props属性改变,一个是state状态改变(这个在生命周期的图片中可以清楚的看到)。
shouldComponentUpdate函数
shouldComponentUpdate函数会在组件更新之前,自动被执行。比如写入下面的代码:
shouldComponentUpdate(){
console.log('shouldComponentUpdate---组件发生改变前执行');
return true;
}
注意
它要求返回一个布尔类型的结果,必须有返回值,上述代码中就直接返回一个true
现在就可以在控制台console里看到结果了,并且结果是每次文本框发生改变时都会随着改变。如果你返回了false,这组件就不会进行更新了。 简单点说,就是返回true,就同意组件更新;返回false,就反对组件更新。
omponentWillUpdate函数 componentWillUpdate在组件更新之前,但shouldComponenUpdate之后被执行。但是如果shouldComponentUpdate返回false,这个函数就不会被执行了。
//shouldComponentUpdate返回true才会被执行。
componentWillUpdate(){
console.log('componentWillUpdate---组件更新前,shouldComponentUpdate函数之后执行')
}
componentDidUpdate
componentDidUpdate在组件更新之后执行,它是组件更新的最后一个环节。
componentDidUpdate(){
console.log('componentDidUpdate----组件更新之后执行')
}
为了方便我们看出结果,可以在每个函数前加上序号。最后我们可以看到控制台输出的结果如下:
1-shouldComponentUpdate---组件发生改变前执行
2-componentWillUpdate---组件更新前,shouldComponentUpdate函数返回true之后执行
3-render----开始挂载渲染
4-componentDidUpdate----组件更新之后执行
componentWillReceiveProps 函数
如果是一个顶层组件,它并没接收任何的props,则不会执行。
componentWillReceiveProps(){
console.log('child - componentWillReceiveProps')
}
也就是说,在组件中有接收通过props传来的参数的时候,在顶层组件再次渲染的时候,就会执行该钩子函数。
3.Unmounting阶段
componentWillUnmount函数
//当组件从页面中删除的时候执行
componentWillUnmount(){
console.log('child - componentWillUnmount')
}