React教程

一、React

尚硅谷

React学习视频:尚硅谷学习视频

尚硅谷:
http://www.atguigu.com/

Vue学习视频(尚硅谷):
https://www.bilibili.com/video/BV1wy4y1D7JT?p=1

百度云课件(尚硅谷资料):
链接:https://pan.baidu.com/s/1vl8_1fcbOX3LM6rwxTY1Pg 
提取码:duhm

gitee笔记项目:
https://gitee.com/happy_sad/react

React官网:
https://react.dev/

React中文官网:
https://react.docschina.org/

Fetch:
https://github.github.io/fetch/

segmentfault 思否:
https://segmentfault.com/

Ant Design:
https://ant.design/docs/react/introduce-cn

material-ui:
https://mui.com/material-ui/getting-started/overview/

一、react_basic

一、hello_react

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>hello_react</title>
</head>

<body>
	<!-- 准备好一个容器 -->
	<div id="test"></div>
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<!-- type为babel -->
	<script type="text/babel">
		// 1.创建虚拟DOM(JSX)
		const VDOM = <h1>Hello,React</h1>/* 不要写引号,因为不是字符串 */
		// 2.渲染虚拟DOM到页面
		ReactDOM.render(VDOM, document.getElementById('test'))
	</script>
</body>

</html>

二、虚拟DOM的两种创建方式

1、使用jsx创建虚拟DOM

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>01_使用jsx创建虚拟DOM</title>
</head>

<body>
	<!-- 准备好一个容器 -->
	<div id="test"></div>
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<!-- type为babel -->
	<script type="text/babel">
		// 1.创建虚拟DOM(JSX)
		const VDOM = (				/* 不要写引号,因为不是字符串 */
			<h1 id="title">
				<span>Hello,React</span>
			</h1>
		)
		// 2.渲染虚拟DOM到页面
		ReactDOM.render(VDOM, document.getElementById('test'))
	</script>
</body>

</html>

2、使用js创建虚拟DOM

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>02_使用js创建虚拟DOM</title>
</head>

<body>
	<!-- 准备好一个容器 -->
	<div id="test"></div>
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>

	<!-- type为babel -->
	<script type="text/javascript">
		// 1.创建虚拟DOM(JS)
		const VDOM = React.createElement('h1', {
      
       id: 'title' }, React.createElement('span', {
      
      }, 'Hello,React'))
		// 2.渲染虚拟DOM到页面
		ReactDOM.render(VDOM, document.getElementById('test'))
	</script>
</body>

</html>

3、虚拟DOM和真实DOM

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>03_虚拟DOM和真实DOM</title>
</head>

<body>
	<!-- 准备好一个容器 -->
	<div id="test"></div>
	<div id="demo"></div>
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<!-- type为babel -->
	<script type="text/babel">
		// 1.创建虚拟DOM(JSX)
		const VDOM = (				/* 不要写引号,因为不是字符串 */
			<h1 id="title">
				<span>Hello,React</span>
			</h1>
		)
		// 2.渲染虚拟DOM到页面
		ReactDOM.render(VDOM, document.getElementById('test'))

		console.log('虚拟DOM', VDOM);
		console.log('虚拟DOM类型', typeof VDOM);
		console.log('虚拟DOM对象', VDOM instanceof Object);

		const TDOM = document.getElementById('demo')
		console.log('真实DOM', TDOM);
		console.log('真实DOM类型', typeof TDOM);
		console.log('真实DOM对象', TDOM instanceof Object);

		/*
			关于虚拟DOM:
			1.本质是Object类型的对象(一般对象)
			2.虚拟DOM比较‘轻’,真实DOM比较‘重’,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性
			3.虚拟DOM最终会被React转化为真实DOM,呈现在页面上
		*/
	</script>
</body>

</html>

三、jsx语法规则

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>jsx语法规则</title>
	<style>
		.title {
      
      
			background-color: orange;
			width: 200px;
		}
	</style>
</head>

<body>
	<!-- 准备好一个容器 -->
	<div id="test"></div>
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<!-- type为babel -->
	<script type="text/babel">
		const myId = 'aTgUigu'
		const myData = 'HeLlo,rEaCt'
		// 1.创建虚拟DOM(JSX)
		const VDOM = (
			<div>
				<h2 className="title" id={
      
      myId.toLowerCase()}>
					<span style={
      
      {
      
       color: 'white', fontSize: '29px' }}>{
      
      myData.toLowerCase()}</span>
				</h2>
				<h2 className="title" id={
      
      myId.toUpperCase()}>
					<span style={
      
      {
      
       color: 'white', fontSize: '29px' }}>{
      
      myData.toUpperCase()}</span>
				</h2>
				<input type="text"></input>
				<Good></Good>
			</div>
		)
		// 2.渲染虚拟DOM到页面
		ReactDOM.render(VDOM, document.getElementById('test'))


		/*
			jsx语法规则:
			1.定义虚拟DOM时,不要写引号
			2.标签中混入JS表达式时要用{}
			3.样式的类名指定不要用class,要用className
			4.内联样式,要用style={
      
      {key:'value'}}的形式去写
			5.虚拟DOM必须只有一个根标签
			6.标签必须闭合
			7.标签首字母
				(1).若小写字母开头,则将该标签转为html同名元素,若html中无该标签对应的同名元素,则报错(<good>123</good>)
				(2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错
		*/
	</script>
</body>

</html>

四、jsx小练习

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>jsx小练习</title>
</head>

<body>
	<!-- 准备好一个容器 -->
	<div id="test"></div>
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<!-- type为babel -->
	<script type="text/babel">
		// 模拟数据
		const data1 = ['Angular', 'React', 'Vue']
		// const data2 = [<li>Angular</li>, <li>React</li>, <li>Vue</li>]

		// 1.创建虚拟DOM(JSX)
		const VDOM = (
			<div>
				<h1>前端js框架列表</h1>
				<ul>
					{
      
      
						data1.map((item, index) => {
      
      
							return <li key={
      
      index}>{
      
      item}</li>
						})
					}
				</ul>
			</div>
		)
		// const VDOM = (
		// 	<div>
		// 		<h1>前端js框架列表</h1>
		// 		<ul>
		// 			{data2}
		// 		</ul>
		// 	</div>
		// )
		// 2.渲染虚拟DOM到页面
		ReactDOM.render(VDOM, document.getElementById('test'))

		/*
			注:【js语句(代码)】与【js表达式】
			1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
				下面这些都是表达式:
					(1).a
					(2).a+b
					(3).demo(1)
					(4).arr.map()
					(5).function test(){}
			2.语句(代码):
				下面这些就是语句(代码):
					(1).if()
					(2).for()
					(3).switch(){case:xxx}
		*/
	</script>
</body>

</html>

五、react中定义组件

1、函数式组件

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>01_函数式组件</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//1.创建函数式组件
		function MyComponent () {
      
      
			console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
			return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
		}
		//2.渲染组件到页面
		ReactDOM.render(<MyComponent></MyComponent>, document.getElementById('test'))
		/*
			执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
					1.React解析组件标签,找到了MyComponent组件。
					2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
		*/
	</script>
</body>

</html>

2、类式组件

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>02_类式组件</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//1.创建类式组件
		class MyComponent extends React.Component {
      
      
			render () {
      
      
				//render是放在哪里的?—— MyComponent的原型对象上,供实例使用。
				//render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。
				console.log('render中的this:', this);
				return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
			}
		}
		//2.渲染组件到页面
		ReactDOM.render(<MyComponent></MyComponent>, document.getElementById('test'))
		/*
			执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
					1.React解析组件标签,找到了MyComponent组件。
					2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
					3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
		*/
	</script>
</body>

</html>

六、组件实例三大属性state

1、state

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>01_state</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//1.创建组件
		class Weather extends React.Component {
      
      

			//构造器调用几次? ———— 刷新初始化页面时调用,1次
			constructor(props) {
      
      
				console.log('constructor', props);
				super(props)
				//初始化状态
				this.state = {
      
       isHot: false, wind: '微风' }
				//解决changeWeather中this指向问题(挂载实例对象)
				this.changeWeatherMount = this.changeWeatherPro.bind(this)
			}

			//render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数
			render () {
      
      
				console.log('render');
				//读取状态
				const isHot = this.state.isHot;
				const wind = this.state.wind;
				// const { isHot, wind } = this.state;
				return <h1 onClick={
      
      this.changeWeatherMount}>今天天气很{
      
      isHot ? '炎热' : '凉爽'}{
      
      wind}</h1>
			}

			//changeWeather调用几次? ———— n次 点几次调几次(放在原型上的)
			changeWeatherPro () {
      
      
				//changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
				//由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
				//类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined

				console.log('changeWeatherPro');
				//获取原来的isHot值
				const isHot = this.state.isHot
				//严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
				this.setState({
      
       isHot: !isHot })
				if (this.state.isHot) {
      
      
					this.setState({
      
       wind: '微风' })
				} else {
      
      
					this.setState({
      
       wind: '台风' })
				}
				console.log('this', this);

				//严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!
				//this.state.isHot = !isHot //这是错误的写法
			}
		}
		//2.渲染组件到页面
		ReactDOM.render(<Weather></Weather>, document.getElementById('test'))

		// const w= new Weather();
		// w.changeWeather();

	</script>
</body>

</html>

2、state的简写方式

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>02_state的简写方式</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//1.创建组件
		class Weather extends React.Component {
      
      
			//01初始化状态(简写,不需要在construct中定义this.state)
			state = {
      
       isHot: false, wind: '微风' }

			render () {
      
      
				const {
      
       isHot, wind } = this.state
				return <h1 onClick={
      
      this.changeWeather}>今天天气很{
      
      isHot ? '炎热' : '凉爽'}{
      
      wind}</h1>
			}

			//02自定义方法————要用赋值语句的形式+箭头函数(简写,不需要在construct中挂载实例对象)
			// 箭头函数没有自己的this,它的this是往外层查找的this
			changeWeather = () => {
      
      
				const isHot = this.state.isHot
				this.setState({
      
       isHot: !isHot })
				if (this.state.isHot) {
      
      
					this.setState({
      
       wind: '微风' })
				} else {
      
      
					this.setState({
      
       wind: '台风' })
				}
				console.log('this', this);
			}
		}
		//2.渲染组件到页面
		ReactDOM.render(<Weather></Weather>, document.getElementById('test'))

	</script>
</body>

</html>

七、组件实例三大属性props

1、props基本使用

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>01_props基本使用</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test1"></div>
	<div id="test2"></div>
	<div id="test3"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Person extends React.Component {
      
      
			render () {
      
      
				console.log('this', this);
				// return (
				// 	<ul>
				// 		<li>姓名:{this.props.name}</li>
				// 		<li>性别:{this.props.sex}</li>
				// 		<li>年龄:{this.props.age + 1}</li>
				// 	</ul>
				// )
				const {
      
       name, age, sex } = this.props
				return (
					<ul>
						<li>姓名:{
      
      name}</li>
						<li>性别:{
      
      sex}</li>
						<li>年龄:{
      
      age + 1}</li>
					</ul>
				)
			}
		}
		//渲染组件到页面
		ReactDOM.render(<Person name="Ling" age={
      
      17} sex="女" />, document.getElementById('test1'))
		ReactDOM.render(<Person name="Jin" age={
      
      18} sex="男"></Person>, document.getElementById('test2'))

		const p = {
      
       name: 'Yu', age: 18, sex: '女' }
		console.log('@', {
      
       ...p });
		// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
		ReactDOM.render(<Person {
      
      ...p} ></Person>, document.getElementById('test3'))
	</script>
</body>

</html>

2、对props进行限制

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>02_对props进行限制</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test1"></div>
	<div id="test2"></div>
	<div id="test3"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>
	<!-- 引入prop-types,用于对组件标签属性进行限制 -->
	<script type="text/javascript" src="../js/prop-types.js"></script>

	<script type="text/babel">
		//创建组件
		class Person extends React.Component {
      
      
			render () {
      
      
				// console.log(this);
				const {
      
       name, age, sex } = this.props
				//props是只读的
				//this.props.name = 'jack' //此行代码会报错,因为props是只读的
				return (
					<ul>
						<li>姓名:{
      
      name}</li>
						<li>性别:{
      
      sex}</li>
						<li>年龄:{
      
      age + 1}</li>
					</ul>
				)
			}
		}
		//对标签属性进行类型、必要性的限制
		Person.propTypes = {
      
      
			name: PropTypes.string.isRequired, //限制name必传,且为字符串
			sex: PropTypes.string,//限制sex为字符串
			age: PropTypes.number,//限制age为数值
			speak: PropTypes.func,//限制speak为函数
		}
		//指定默认标签属性值
		Person.defaultProps = {
      
      
			sex: '男',//sex默认值为男
			age: 18 //age默认值为18
		}
		//渲染组件到页面
		ReactDOM.render(<Person name={
      
      100} speak={
      
      speak} />, document.getElementById('test1'))
		ReactDOM.render(<Person name="tom" age={
      
      18} sex="女"></Person>, document.getElementById('test2'))

		const p = {
      
       name: '老刘', age: 18, sex: '女' }
		// console.log('@',...p);
		// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
		ReactDOM.render(<Person {
      
      ...p}></Person>, document.getElementById('test3'))

		function speak () {
      
      
			console.log('我说话了');
		}
	</script>
</body>

</html>

3、props的简写方式

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>03_props的简写方式</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test1"></div>
	<div id="test2"></div>
	<div id="test3"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>
	<!-- 引入prop-types,用于对组件标签属性进行限制 -->
	<script type="text/javascript" src="../js/prop-types.js"></script>

	<script type="text/babel">
		//创建组件
		class Person extends React.Component {
      
      

			constructor(props) {
      
      
				//构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
				// console.log(props);
				super(props)
				console.log('constructor', this.props);
			}

			//对标签属性进行类型、必要性的限制
			static propTypes = {
      
      
				name: PropTypes.string.isRequired, //限制name必传,且为字符串
				sex: PropTypes.string,//限制sex为字符串
				age: PropTypes.number,//限制age为数值
			}

			//指定默认标签属性值
			static defaultProps = {
      
      
				sex: '男',//sex默认值为男
				age: 18 //age默认值为18
			}

			render () {
      
      
				// console.log(this);
				const {
      
       name, age, sex } = this.props
				//props是只读的
				//this.props.name = 'jack' //此行代码会报错,因为props是只读的
				return (
					<ul>
						<li>姓名:{
      
      name}</li>
						<li>性别:{
      
      sex}</li>
						<li>年龄:{
      
      age + 1}</li>
					</ul>
				)
			}
		}

		//渲染组件到页面
		ReactDOM.render(<Person name="jerry" />, document.getElementById('test1'))
	</script>
</body>

</html>

4、函数组件使用props

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>04_函数组件使用props</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test1"></div>
	<div id="test2"></div>
	<div id="test3"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>
	<!-- 引入prop-types,用于对组件标签属性进行限制 -->
	<script type="text/javascript" src="../js/prop-types.js"></script>

	<script type="text/babel">
		//创建组件
		function Person (props) {
      
      
			console.log("props", props)
			const {
      
       name, age, sex } = props
			return (
				<ul>
					<li>姓名:{
      
      name}</li>
					<li>性别:{
      
      sex}</li>
					<li>年龄:{
      
      age}</li>
				</ul>
			)
		}
		Person.propTypes = {
      
      
			name: PropTypes.string.isRequired, //限制name必传,且为字符串
			sex: PropTypes.string,//限制sex为字符串
			age: PropTypes.number,//限制age为数值
		}

		//指定默认标签属性值
		Person.defaultProps = {
      
      
			sex: '男',//sex默认值为男
			age: 18 //age默认值为18
		}
		//渲染组件到页面
		ReactDOM.render(<Person name="jerry" />, document.getElementById('test1'))
	</script>
</body>

</html>

八、组件实例三大属性refs

1、字符串形式的ref

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>01_字符串形式的ref</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Demo extends React.Component {
      
      
			//展示左侧输入框的数据
			// <input id="input11" type="text" placeholder="点击按钮提示数据" />&nbsp;
			// showData = () => {
      
      
			// 	const input11 = document.getElementById("input11")
			// 	alert(input11.value)
			// }
			showData = () => {
      
      
				console.log(this.refs.input1)
				// const input1 = this.refs.input1
				const {
      
       input1 } = this.refs
				alert(input1.value)
			}
			//展示右侧输入框的数据
			showData2 = () => {
      
      
				console.log(this.refs.input2)
				const {
      
       input2 } = this.refs
				alert(input2.value)
			}
			render () {
      
      
				return (
					<div>
						<input ref="input1" type="text" placeholder="点击按钮提示数据" />&nbsp;
						<button onClick={
      
      this.showData}>点我提示左侧的数据</button>&nbsp;
						<input ref="input2" onBlur={
      
      this.showData2} type="text" placeholder="失去焦点提示数据" />
					</div>
				)
			}
		}
		//渲染组件到页面
		ReactDOM.render(<Demo></Demo>, document.getElementById('test'))
	</script>
</body>

</html>

2、回调函数形式的ref

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>02_回调函数形式的ref</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Demo extends React.Component {
      
      
			//展示左侧输入框的数据
			showData = () => {
      
      
				const {
      
       input1 } = this
				alert(input1.value)
			}
			//展示右侧输入框的数据
			showData2 = () => {
      
      
				const {
      
       input2 } = this
				alert(input2.value)
			}
			render () {
      
      
				return (
					<div>
						{
      
      /*<input ref={(currentNode)=>{console.log(currentNode);}} type="text" placeholder="点击按钮提示数据" />&nbsp;*/}
						<input ref={
      
      (currentNode) => {
      
       this.input1 = currentNode; }} type="text" placeholder="点击按钮提示数据" />&nbsp;
						<button onClick={
      
      this.showData}>点我提示左侧的数据</button>&nbsp;
						<input onBlur={
      
      this.showData2} ref={
      
      c => this.input2 = c} type="text" placeholder="失去焦点提示数据" />&nbsp;
					</div>
				)
			}
		}
		//渲染组件到页面
		ReactDOM.render(<Demo a="1" b="2" />, document.getElementById('test'))
	</script>
</body>

</html>

3、回调ref中回调执行次数的问题

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>03_回调ref中回调执行次数的问题</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Demo extends React.Component {
      
      

			state = {
      
       isHot: false }

			showInfo = () => {
      
      
				const {
      
       input1 } = this
				alert(input1.value)
			}

			changeWeather = () => {
      
      
				//获取原来的状态
				const {
      
       isHot } = this.state
				//更新状态
				this.setState({
      
       isHot: !isHot })
			}

			saveInput = (c) => {
      
      
				this.input1 = c;
				console.log('@', c);
			}

			render () {
      
      
				const {
      
       isHot } = this.state
				return (
					<div>
						<h2>今天天气很{
      
      isHot ? '炎热' : '凉爽'}</h2>
						{
      
      /*<input ref={(c)=>{this.input1 = c;console.log('@',c);}} type="text"/><br/><br/>*/}
						<input ref={
      
      this.saveInput} type="text" /><br /><br />
						<button onClick={
      
      this.showInfo}>点我提示输入的数据</button>
						<button onClick={
      
      this.changeWeather}>点我切换天气</button>
					</div>
				)
			}
		}
		//渲染组件到页面
		ReactDOM.render(<Demo />, document.getElementById('test'))
	</script>
</body>

</html>

4、createRef的使用

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>04_createRef的使用</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Demo extends React.Component {
      
      
			/* 
				React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
			 */
			myRef = React.createRef()
			myRef2 = React.createRef()
			//展示左侧输入框的数据
			showData = () => {
      
      
				alert(this.myRef.current.value);
			}
			//展示右侧输入框的数据
			showData2 = () => {
      
      
				alert(this.myRef2.current.value);
			}
			render () {
      
      
				return (
					<div>
						<input ref={
      
      this.myRef} type="text" placeholder="点击按钮提示数据" />&nbsp;
						<button onClick={
      
      this.showData}>点我提示左侧的数据</button>&nbsp;
						<input onBlur={
      
      this.showData2} ref={
      
      this.myRef2} type="text" placeholder="失去焦点提示数据" />&nbsp;
					</div>
				)
			}
		}
		//渲染组件到页面
		ReactDOM.render(<Demo a="1" b="2" />, document.getElementById('test'))
	</script>
</body>

</html>

九、react中的事件处理

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>事件处理</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Demo extends React.Component{
      
      
			/* 
				(1).通过onXxx属性指定事件处理函数(注意大小写)
						a.React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —————— 为了更好的兼容性
						b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了的高效
				(2).通过event.target得到发生事件的DOM元素对象 ——————————不要过度使用ref
			 */
			//创建ref容器
			myRef = React.createRef()
			myRef2 = React.createRef()

			//展示左侧输入框的数据
			showData = (event)=>{
      
      
				console.log(event.target);
				alert(this.myRef.current.value);
			}

			//展示右侧输入框的数据
			showData2 = (event)=>{
      
      
				alert(event.target.value);
			}

			render(){
      
      
				return(
					<div>
						<input ref={
      
      this.myRef} type="text" placeholder="点击按钮提示数据"/>&nbsp;
						<button onClick={
      
      this.showData}>点我提示左侧的数据</button>&nbsp;
						<input onBlur={
      
      this.showData2} type="text" placeholder="失去焦点提示数据"/>&nbsp;
					</div>
				)
			}
		}
		//渲染组件到页面
		ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test'))
	</script>
</body>
</html>

十、react中收集表单数据

1、非受控组件

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>01_非受控组件</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Login extends React.Component {
      
      
			handleSubmit = (event) => {
      
      
				event.preventDefault() //阻止表单提交
				const {
      
       username, password } = this
				alert(`你输入的用户名是:${ 
        username.value},你输入的密码是:${ 
        password.value}`)
			}
			render () {
      
      
				return (
					<form action="http://www.atguigu.com" onSubmit={
      
      this.handleSubmit}>
						用户名:<input ref={
      
      c => this.username = c} type="text" name="username" />
						密码:<input ref={
      
      c => this.password = c} type="password" name="password" />
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login />, document.getElementById('test'))
	</script>
</body>

</html>

2、受控组件

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>02_受控组件</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Login extends React.Component {
      
      

			//初始化状态
			state = {
      
      
				username: '', //用户名
				password: '' //密码
			}

			//保存用户名到状态中
			saveUsername = (event) => {
      
      
				console.log("saveUsername")
				this.setState({
      
       username: event.target.value })
			}

			//保存密码到状态中
			savePassword = (event) => {
      
      
				console.log("savePassword")
				this.setState({
      
       password: event.target.value })
			}

			//表单提交的回调
			handleSubmit = (event) => {
      
      
				event.preventDefault() //阻止表单提交
				const {
      
       username, password } = this.state
				alert(`你输入的用户名是:${ 
        username},你输入的密码是:${ 
        password}`)
			}

			render () {
      
      
				return (
					<form action="http://www.atguigu.com" onSubmit={
      
      this.handleSubmit}>
						用户名:<input onChange={
      
      this.saveUsername} type="text" name="username" />
						密码:<input onChange={
      
      this.savePassword} type="password" name="password" />
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login />, document.getElementById('test'))
	</script>
</body>

</html>

十一、高阶函数_函数柯里化

1、高阶函数_函数柯里化

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>01_高阶函数_函数柯里化</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//#region 
		/* 
			高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
							1.若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
							2.若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
							常见的高阶函数有:Promise、setTimeout、arr.map()等等

			函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。 
				function sum(a){
					return(b)=>{
						return (c)=>{
							return a+b+c
						}
					}
				}
			*/
		//#endregion
		//创建组件
		class Login extends React.Component {
      
      
			//初始化状态
			state = {
      
      
				username: '', //用户名
				password: '' //密码
			}

			//保存表单数据到状态中
			saveFormData = (dataType) => {
      
      
				// console.log('dataType:' + dataType)
				return (event) => {
      
      
					this.setState({
      
       [dataType]: event.target.value })
				}
			}

			//表单提交的回调
			handleSubmit = (event) => {
      
      
				event.preventDefault() //阻止表单提交
				const {
      
       username, password } = this.state
				alert(`你输入的用户名是:${ 
        username},你输入的密码是:${ 
        password}`)
			}
			render () {
      
      
				return (
					<form onSubmit={
      
      this.handleSubmit}>
						用户名:<input onChange={
      
      this.saveFormData('username')} type="text" name="username" />
						密码:<input onChange={
      
      this.saveFormData('password')} type="password" name="password" />
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login />, document.getElementById('test'))
	</script>
</body>

</html>

2、不用函数柯里化的实现

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>02_不用函数柯里化的实现</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Login extends React.Component {
      
      
			//初始化状态
			state = {
      
      
				username: '', //用户名
				password: '' //密码
			}

			//保存表单数据到状态中
			saveFormData = (dataType, event) => {
      
      
				this.setState({
      
       [dataType]: event.target.value })
			}

			//表单提交的回调
			handleSubmit = (event) => {
      
      
				event.preventDefault() //阻止表单提交
				const {
      
       username, password } = this.state
				alert(`你输入的用户名是:${ 
        username},你输入的密码是:${ 
        password}`)
			}
			render () {
      
      
				return (
					<form onSubmit={
      
      this.handleSubmit}>
						用户名:<input onChange={
      
      (event) => {
      
       this.saveFormData('username', event); }} type="text" name="username" />
						密码:<input onChange={
      
      event => this.saveFormData('password', event)} type="password" name="password" />
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login />, document.getElementById('test'))
	</script>
</body>

</html>

十二、组件的生命周期

1、引出生命周期

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>01_引出生命周期</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		//生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
		class Life extends React.Component {
      
      

			state = {
      
       opacity: 1 }

			death = () => {
      
      
				//卸载组件
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			//组件挂完毕(组件挂载在页面之后调用)
			componentDidMount () {
      
      
				console.log('componentDidMount');
				this.timer = setInterval(() => {
      
      
					//获取原状态(此处不可用const,因为使用const后不可更改)
					// let声明的变量可以改变,值和类型都可以改变;而const声明的常量不可以改变,这意味着,const一旦声明,就必须立即初始化,不能以后再赋值
					let {
      
       opacity } = this.state
					//减小0.1
					opacity -= 0.1
					if (opacity <= 0) opacity = 1
					//设置新的透明度
					this.setState({
      
       opacity })
				}, 200);
			}

			//组件将要卸载
			componentWillUnmount () {
      
      
				console.log('componentWillUnmount');
				//清除定时器
				clearInterval(this.timer)
			}

			//初始化渲染、状态更新之后
			render () {
      
      
				console.log('render');
				return (
					<div>
						<h2 style={
      
      {
      
       opacity: this.state.opacity }}>React学不会怎么办?</h2>
						<button onClick={
      
      this.death}>不活了</button>
					</div>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Life />, document.getElementById('test'))
	</script>
</body>

</html>

2、react生命周期(旧)

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>02_react生命周期(旧)</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		/* 
				1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
									1.	constructor()
									2.	componentWillMount()
									3.	render()
									4.	componentDidMount() =====> 常用
													一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
				2. 更新阶段: 由组件内部this.setSate()或父组件render触发
									1.	shouldComponentUpdate()
									2.	componentWillUpdate()
									3.	render() =====> 必须使用的一个
									4.	componentDidUpdate()
				3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
									1.	componentWillUnmount()  =====> 常用
													一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
		*/
		//创建组件
		class Count extends React.Component {
      
      

			//构造器
			constructor(props) {
      
      
				console.log('11---Count---constructor');
				super(props)
				//初始化状态
				this.state = {
      
       count: 0 }
			}

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

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

			//强制更新按钮的回调
			force = () => {
      
      
				console.log('31---Count---forceUpdate')
				this.forceUpdate()
			}

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

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

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

			//控制组件更新的“阀门”(需要返回true打开阀门,返回false的话不执行+1)
			shouldComponentUpdate () {
      
      
				console.log('21---Count---shouldComponentUpdate');
				return true
			}

			//组件将要更新的钩子
			componentWillUpdate () {
      
      
				console.log('22、32---Count---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate () {
      
      
				console.log('24、34---Count---componentDidUpdate');
			}

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

		//父组件A
		class A extends React.Component {
      
      
			//初始化状态
			state = {
      
       carName: '奔驰' }

			changeCar = () => {
      
      
				this.setState({
      
       carName: '奥拓' })
			}

			render () {
      
      
				return (
					<div>
						<div>我是A组件</div>
						<button onClick={
      
      this.changeCar}>换车</button>
						<B carName={
      
      this.state.carName} />
					</div>
				)
			}
		}

		//子组件B
		class B extends React.Component {
      
      
			//组件将要接收新的props的钩子
			componentWillReceiveProps (props) {
      
      
				console.log('41---B---componentWillReceiveProps', props);
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate () {
      
      
				console.log('42---B---shouldComponentUpdate');
				return true
			}
			//组件将要更新的钩子
			componentWillUpdate () {
      
      
				console.log('44---B---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate () {
      
      
				console.log('45---B---componentDidUpdate');
			}

			render () {
      
      
				console.log('43---B---render');
				return (
					<div>我是B组件,接收到的车是:{
      
      this.props.carName}</div>
				)
			}
		}

		//渲染组件Count/A
		ReactDOM.render(<Count />, document.getElementById('test'))
		// ReactDOM.render(<A />, document.getElementById('test'))
	</script>
</body>

</html>

3、react生命周期(旧)图

image-20220729105218531

4、react生命周期(新1)

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>03_react生命周期(新1)</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		/* 
				1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
									1.	constructor()
									2.	UNSAFE_componentWillMount()
									3.	render()
									4.	componentDidMount() =====> 常用
													一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
				2. 更新阶段: 由组件内部this.setSate()或父组件render触发
									1.	shouldComponentUpdate()
									2.	UNSAFE_componentWillUpdate()
									3.	render() =====> 必须使用的一个
									4.	componentDidUpdate()
				3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
									1.	componentWillUnmount()  =====> 常用
													一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
		*/
		//创建组件
		class Count extends React.Component {
      
      

			//构造器
			constructor(props) {
      
      
				console.log('11---Count---constructor');
				super(props)
				//初始化状态
				this.state = {
      
       count: 0 }
			}

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

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

			//强制更新按钮的回调
			force = () => {
      
      
				console.log('31---Count---forceUpdate')
				this.forceUpdate()
			}

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

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

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

			//控制组件更新的“阀门”(需要返回true打开阀门,返回false的话不执行+1)
			shouldComponentUpdate () {
      
      
				console.log('21---Count---shouldComponentUpdate');
				return true
			}

			//组件将要更新的钩子
			UNSAFE_componentWillUpdate () {
      
      
				console.log('22、32---Count---UNSAFE_componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate () {
      
      
				console.log('24、34---Count---componentDidUpdate');
			}

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

		//父组件A
		class A extends React.Component {
      
      
			//初始化状态
			state = {
      
       carName: '奔驰' }

			changeCar = () => {
      
      
				this.setState({
      
       carName: '奥拓' })
			}

			render () {
      
      
				return (
					<div>
						<div>我是A组件</div>
						<button onClick={
      
      this.changeCar}>换车</button>
						<B carName={
      
      this.state.carName} />
					</div>
				)
			}
		}

		//子组件B
		class B extends React.Component {
      
      
			//组件将要接收新的props的钩子
			UNSAFE_componentWillReceiveProps (props) {
      
      
				console.log('41---B---UNSAFE_componentWillReceiveProps', props);
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate () {
      
      
				console.log('42---B---shouldComponentUpdate');
				return true
			}
			//组件将要更新的钩子
			UNSAFE_componentWillUpdate () {
      
      
				console.log('44---B---UNSAFE_componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate () {
      
      
				console.log('45---B---componentDidUpdate');
			}

			render () {
      
      
				console.log('43---B---render');
				return (
					<div>我是B组件,接收到的车是:{
      
      this.props.carName}</div>
				)
			}
		}

		//渲染组件Count/A
		ReactDOM.render(<Count />, document.getElementById('test'))
		// ReactDOM.render(<A />, document.getElementById('test'))
	</script>
</body>

</html>

5、react生命周期(新2)

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>03_react生命周期(新2)</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Count extends React.Component {
      
      
			/* 
				1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
									1.	constructor()
									2.	getDerivedStateFromProps
									3.	render()
									4.	componentDidMount() =====> 常用
													一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
				2. 更新阶段: 由组件内部this.setSate()或父组件render触发
									1.	getDerivedStateFromProps
									2.	shouldComponentUpdate
									3.	render() =====> 必须使用的一个
									4.	getSnapshotBeforeUpdate
									5.  componentDidUpdate
				3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
									1.	componentWillUnmount()  =====> 常用
													一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
		*/
			//构造器
			constructor(props) {
      
      
				console.log('11---Count---constructor');
				super(props)
				//初始化状态
				this.state = {
      
       count: 0 }
			}

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

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

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

			//若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
			static getDerivedStateFromProps (props, state) {
      
      
				console.log('12、21、31---getDerivedStateFromProps', props, state);
				return null
			}

			//在更新之前获取快照('任何值都可以作为快照值')
			getSnapshotBeforeUpdate () {
      
      
				console.log('24、33---getSnapshotBeforeUpdate');
				return 'atguigu'
			}

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

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

			//控制组件更新的“阀门”
			shouldComponentUpdate () {
      
      
				console.log('22---Count---shouldComponentUpdate');
				return true
			}

			//组件更新完毕的钩子(前一个Props,前一个State、前一个snapshotValue(快照值))
			componentDidUpdate (preProps, preState, snapshotValue) {
      
      
				console.log('25、34---Count---componentDidUpdate', preProps, preState, snapshotValue);
			}

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

		//渲染组件Count/A
		ReactDOM.render(<Count count={
      
      199} />, document.getElementById('test'))
		// ReactDOM.render(<A />, document.getElementById('test'))
		//渲染组件
	</script>
</body>

</html>

6、react生命周期(新)图

image-20220729110225677

7、getSnapshotBeforeUpdate

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>04_getSnapshotBeforeUpdate的使用场景</title>
	<style>
		.list {
      
      
			width: 200px;
			height: 150px;
			background-color: skyblue;
			overflow: auto;
		}

		.news {
      
      
			height: 30px;
		}
	</style>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		class NewsList extends React.Component {
      
      

			state = {
      
       newsArr: [] }

			componentDidMount () {
      
      
				setInterval(() => {
      
      
					//获取原状态
					const {
      
       newsArr } = this.state
					//模拟一条新闻
					const news = '新闻' + (newsArr.length + 1)
					//更新状态
					this.setState({
      
       newsArr: [news, ...newsArr] })
				}, 1000);
			}

			getSnapshotBeforeUpdate () {
      
      
				return this.refs.list.scrollHeight
			}

			componentDidUpdate (preProps, preState, height) {
      
      
				this.refs.list.scrollTop += this.refs.list.scrollHeight - height
			}

			render () {
      
      
				return (
					<div className="list" ref="list">
						{
      
      
							this.state.newsArr.map((n, index) => {
      
      
								return <div key={
      
      index} className="news">{
      
      n}</div>
							})
						}
					</div>
				)
			}
		}
		ReactDOM.render(<NewsList />, document.getElementById('test'))
	</script>
</body>

</html>

十三、DOM的Diffing算法

1、验证Diffing算法

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title>01_验证Diffing算法</title>
</head>

<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		class Time extends React.Component {
      
      
			state = {
      
       date: new Date() }

			componentDidMount () {
      
      
				setInterval(() => {
      
      
					this.setState({
      
      
						date: new Date()
					})
				}, 1000)
			}

			render () {
      
      
				return (
					<div>
						<h1>hello</h1>
						<input type="text" />
						<span>现在是:{
      
      this.state.date.toTimeString()}<input type="text" /></span>
					</div>
				)
			}
		}

		ReactDOM.render(<Time />, document.getElementById('test'))
	</script>
</body>

</html>

2、key的作用

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title>02_key的作用</title>
</head>

<body>
	<div id="test"></div>
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		/*
		 经典面试题:
				1). react/vue中的key有什么作用?(key的内部原理是什么?)
				2). 为什么遍历列表时,key最好不要用index?
			  
				1. 虚拟DOM中key的作用:
						1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
	
						2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 
													随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
	
										a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
													(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
													(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
	
										b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
													根据数据创建新的真实DOM,随后渲染到到页面
										
				2. 用index作为key可能会引发的问题:
									1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
													会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
	
									2. 如果结构中还包含输入类的DOM:
													会产生错误DOM更新 ==> 界面有问题。
													
									3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
										仅用于渲染列表用于展示,使用index作为key是没有问题的。
						
				3. 开发中如何选择key?:
									1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
									2.如果确定只是简单的展示数据,用index也是可以的。
		 */

		/* 
			慢动作回放----使用index索引值作为key
	
				初始数据:
						{id:1,name:'小张',age:18},
						{id:2,name:'小李',age:19},
				初始的虚拟DOM:
						<li key=0>小张---18<input type="text"/></li>
						<li key=1>小李---19<input type="text"/></li>
	
				更新后的数据:
						{id:3,name:'小王',age:20},
						{id:1,name:'小张',age:18},
						{id:2,name:'小李',age:19},
				更新数据后的虚拟DOM:
						<li key=0>小王---20<input type="text"/></li>
						<li key=1>小张---18<input type="text"/></li>
						<li key=2>小李---19<input type="text"/></li>
	
		-----------------------------------------------------------------
	
		慢动作回放----使用id唯一标识作为key
	
				初始数据:
						{id:1,name:'小张',age:18},
						{id:2,name:'小李',age:19},
				初始的虚拟DOM:
						<li key=1>小张---18<input type="text"/></li>
						<li key=2>小李---19<input type="text"/></li>
	
				更新后的数据:
						{id:3,name:'小王',age:20},
						{id:1,name:'小张',age:18},
						{id:2,name:'小李',age:19},
				更新数据后的虚拟DOM:
						<li key=3>小王---20<input type="text"/></li>
						<li key=1>小张---18<input type="text"/></li>
						<li key=2>小李---19<input type="text"/></li>
	
	
		 */
		class Person extends React.Component {
      
      

			state = {
      
      
				persons: [
					{
      
       id: 1, name: '小张', age: 18 },
					{
      
       id: 2, name: '小李', age: 19 },
				]
			}

			add = () => {
      
      
				const {
      
       persons } = this.state
				const p = {
      
       id: persons.length + 1, name: '小王', age: 20 }
				this.setState({
      
       persons: [p, ...persons] })
			}

			render () {
      
      
				return (
					<div>
						<h2>展示人员信息</h2>
						<button onClick={
      
      this.add}>添加一个小王</button>
						<h3>使用index(索引值)作为key</h3>
						<ul>
							{
      
      
								this.state.persons.map((personObj, index) => {
      
      
									return <li key={
      
      index}>{
      
      personObj.name}---{
      
      personObj.age}<input type="text" /></li>
								})
							}
						</ul>
						<hr />
						<hr />
						<h3>使用id(数据的唯一标识)作为key</h3>
						<ul>
							{
      
      
								this.state.persons.map((personObj) => {
      
      
									return <li key={
      
      personObj.id}>{
      
      personObj.name}---{
      
      personObj.age}<input type="text" /></li>
								})
							}
						</ul>
					</div>
				)
			}
		}

		ReactDOM.render(<Person />, document.getElementById('test'))
	</script>
</body>

</html>

十四、复习

1、类的基本知识

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<title>1_类的基本知识</title>
</head>

<body>
	<script type="text/javascript">
		/* 
			总结:
				1.类中的构造器不是必须要写的,要对实例进行一些初始化的操作,如添加指定属性时才写。
				2.如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的。
				3.类中所定义的方法,都放在了类的原型对象上,供实例去使用。
		*/
		//创建一个Person类
		class Person {
      
      
			//构造器方法
			constructor(name, age) {
      
      
				//构造器中的this是谁?—— 类的实例对象
				this.name = name
				this.age = age
			}
			//一般方法
			speak () {
      
      
				//speak方法放在了哪里?——类的原型对象上,供实例使用
				//通过Person实例调用speak时,speak中的this就是Person实例
				console.log(`我叫${ 
        this.name},我年龄是${ 
        this.age}`);
			}
		}
		const p = new Person('Jin', 18);
		console.log(p);
		p.speak();

		//创建一个Student类,继承于Person类
		class Student extends Person {
      
      
			constructor(name, age, grade) {
      
      
				super(name, age)
				this.grade = grade
				this.school = '尚硅谷'
			}
			//重写从父类继承过来的方法
			speak () {
      
      
				console.log(`我叫${ 
        this.name},我年龄是${ 
        this.age},我读的是${ 
        this.grade}年级`);
				this.study()
			}
			study () {
      
      
				//study方法放在了哪里?——类的原型对象上,供实例使用
				//通过Student实例调用study时,study中的this就是Student实例
				console.log('我很努力的学习');
			}
		}
		const s = new Student('Jin', 18, '大一');
		console.log(s);
		s.speak();

		class Car {
      
      
			constructor(name, price) {
      
      
				this.name = name
				this.price = price
				// this.wheel = 4
			}
			//类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1
			a = 1
			wheel = 4
			static demo = 100
		}
		const c1 = new Car('奔驰c63', 199)
		console.log(c1);
		console.log(Car.demo);
	</script>
</body>

</html>

2、原生事件绑定

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<title>2_原生事件绑定</title>
</head>

<body>
	<button id="btn1">按钮1</button>
	<button id="btn2">按钮2</button>
	<button onclick="demo()">按钮3</button>

	<script type="text/javascript">
		const btn1 = document.getElementById('btn1')
		btn1.addEventListener('click', () => {
      
      
			alert('按钮1被点击了')
		})

		const btn2 = document.getElementById('btn2')
		btn2.onclick = () => {
      
      
			alert('按钮2被点击了')
		}

		function demo () {
      
      
			alert('按钮3被点击了')
		}

	</script>
</body>

</html>

3、类方法中的this指向

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<title>3_类方法中的this指向</title>
</head>

<body>
	<script type="text/javascript">
		class Person {
      
      
			constructor(name, age) {
      
      
				this.name = name
				this.age = age
			}
			study () {
      
      
				//study方法放在了哪里?——类的原型对象上,供实例使用
				//通过Person实例调用study时,study中的this就是Person实例
				console.log(this);
			}
		}

		const p1 = new Person('tom', 18)
		p1.study() //通过实例调用study方法
		const x = p1.study
		x()

	</script>
</body>

</html>

4、展开运算符

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<title>4_展开运算符</title>
</head>

<body>
	<script type="text/javascript">
		let arr1 = [1, 3, 5, 7, 9]
		let arr2 = [2, 4, 6, 8, 10]
		console.log(...arr1); //展开一个数组
		let arr3 = [...arr1, ...arr2]//连接数组
		console.log(arr3)

		//在函数中使用
		function sum (...numbers) {
      
      
			return numbers.reduce((preValue, currentValue) => {
      
      
				return preValue + currentValue
			})
		}
		console.log(sum(1, 2, 3, 4));

		//构造字面量对象时使用展开语法
		let person = {
      
       name: 'tom', age: 18 }
		let person2 = {
      
       ...person }
		//console.log(...person); //报错,展开运算符不能展开对象
		console.log(person2);
		person.name = 'jerry'
		console.log(person);

		//合并
		let person3 = {
      
       ...person, name: 'jack', address: "地球" }
		console.log(person3);

	</script>
</body>

</html>

5、对象相关的知识

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<title>5_对象相关的知识</title>
</head>

<body>
	<script type="text/javascript">
		let a = 'name'

		let obj = {
      
      } // {name:'tom'}
		obj[a] = 'tom'
		console.log(obj);

	</script>
</body>

</html>

6、演示函数的柯里化

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<title>6_演示函数的柯里化</title>
</head>

<body>
	<script type="text/javascript">
		/* function sum(a,b,c){
			return a+b+c
		} */

		function sum (a) {
      
      
			return (b) => {
      
      
				return (c) => {
      
      
					return a + b + c
				}
			}
		}
		const result = sum(1)(2)(3)
		console.log(result);
	</script>
</body>

</html>

二、react_staging

一、01_react脚手架

1、创建项目并启动

#全局安装
npm install -g create-react-app	或者
npm install create-react-app -g
#切换到想要创建项目的目录
cd Desktop\Studying\React\源码\React
#使用命令
create-react-app hello-react
#进入项文件夹
cd hello-react
#启动项目
npm start 或者
yarn start

注:需要使用node.js的14版本以上的(之前使用的hi是12.18.1(本人使用的是NVM控制node.js版本号))

image-20220801115039284

重新全局安装和创建项目

image-20220801115554088

image-20220801115921884

成功显示

image-20220801120032751

扫描二维码关注公众号,回复: 15429592 查看本文章

image-20220801120117994

2、脚手架自带文件

public/index.html

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="utf-8" />
	<!-- %PUBLIC_URL%代表public文件夹的路径 -->
	<!-- <link rel="icon" href="./favicon.ico" /> -->
	<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
	<!-- 开启理想视口,用于做移动端网页的适配 -->
	<meta name="viewport" content="width=device-width, initial-scale=1" />
	<!-- 用于配置浏览器页签+地址栏的颜色(仅支持安卓手机浏览器) -->
	<meta name="theme-color" content="red" />
	<meta name="description" content="Web site created using create-react-app" />
	<!-- 用于指定网页添加到苹果手机主屏幕后的图标(仅支持苹果手机浏览器) -->
	<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
	<!-- 应用加壳时的配置文件 -->
	<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
	<title>React App</title>
</head>

<body>
	<!-- 若llq不支持js则展示标签中的内容 -->
	<noscript>You need to enable JavaScript to run this app.</noscript>
	<div id="root"></div>
</body>

</html>

src/App.js

import logo from './logo.svg';
import './App.css';

function App() {
    
    
  return (
    <div className="App">
      <header className="App-header">
        <img src={
    
    logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
	// <React.StrictMode></React.StrictMode>可以检查自己写的是否符合ReactApi,然后给予提示
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();

二、02_src_hello_react

三、03_src_TodoList案例

1.拆分组件、实现静态组件,注意:className、style的写法
2.动态初始化列表,如何确定将数据放在哪个组件的state中?
            ——某个组件使用:放在其自身的state中
            ——某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)
3.关于父子之间通信:
        1.【父组件】给【子组件】传递数据:通过props传递
        2.【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数
4.注意defaultChecked(只有在第一次执行起作用,在以后都不起作用) 和 checked的区别,类似的还有:defaultValue 和 value
5.状态在哪里,操作状态的方法就在哪里

四、04_src_配置代理

# react脚手架配置代理总结
# 方法一
>package.json中追加如下配置
​```json
"proxy":"http://localhost:5000"
​```
说明:
1. 优点:配置简单,前端请求资源时可以不加任何前缀。
2. 缺点:不能配置多个代理。
3. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)
# 方法二
1. 第一步:创建代理配置文件

在src下创建配置文件:src/setupProxy.js

2. 编写setupProxy.js配置具体代理规则:
const proxy = require('http-proxy-middleware')
module.exports = function(app) {
    
    
  app.use(
    proxy('/api1', {
    
      //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
      target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
      changeOrigin: true, //控制服务器接收到的请求头中host字段的值
      /*
      	changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
      	changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
      	changeOrigin默认值为false,但我们一般将changeOrigin值设为true
      */
      pathRewrite: {
    
    '^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
    }),
    proxy('/api2', {
    
     
      target: 'http://localhost:5001',
      changeOrigin: true,
      pathRewrite: {
    
    '^/api2': ''}
    })
  )
}
说明:
1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
2. 缺点:配置繁琐,前端请求资源时必须加前缀。

五、05_src_github搜索案例_axios

六、06_src_github搜索案例_pubsub

七、07_src_github搜索案例_fetch

# 1.xhr		fetch
# 2.ajax	axios

## 二、github搜索案例相关知识点
1.设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办。
2.ES6小知识点:解构赋值+重命名
        let obj = {
    
    a:{
    
    b:1}}
        const {
    
    a} = obj; //传统解构赋值
        const {
    
    a:{
    
    b}} = obj; //连续解构赋值
        const {
    
    a:{
    
    b:value}} = obj; //连续解构赋值+重命名
3.消息订阅与发布机制
        1.先订阅,再发布(理解:有一种隔空对话的感觉)
        2.适用于任意组件间通信
        3.要在组件的componentWillUnmount中取消订阅
4.fetch发送请求(关注分离的设计思想)
        try {
    
    
            const response= await fetch(`/api1/search/users2?q=${
      
      keyWord}`)
            const data = await response.json()
            console.log(data);
        } catch (error) {
    
    
            console.log('请求出错',error);
        }

八、08_src_路由的基本使用

## 三、路由的基本使用
1.明确好界面中的导航区、展示区
2.导航区的a标签改为Link标签
        <Link to="/xxxxx">Demo</Link>
3.展示区写Route标签进行路径的匹配
        <Route path='/xxxx' component={
    
    Demo}/>
4.<App>的最外侧包裹了一个<BrowserRouter><HashRouter>
            
## 十三、BrowserRouter与HashRouter的区别
1.底层原理不一样:
        BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
        HashRouter使用的是URL的哈希值。
2.path表现形式不一样
        BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
        HashRouter的路径包含#,例如:localhost:3000/#/demo/test
3.刷新后对路由state参数的影响
        (1).BrowserRouter没有任何影响,因为state保存在history对象中。
        (2).HashRouter刷新后会导致路由state参数的丢失!!!
4.备注:HashRouter可以用于解决一些路径错误相关的问题。

九、09_src_NavLink的使用

## 四、路由组件与一般组件
1.写法不同:
        一般组件:<Demo/>
        路由组件:<Route path="/demo" component={
    
    Demo}/>
2.存放位置不同:
        一般组件:components
        路由组件:pages
3.接收到的props不同:
        一般组件:写组件标签时传递了什么,就能收到什么
        路由组件:接收到三个固定的属性
                history:
                            go: ƒ go(n)
                            goBack: ƒ goBack()
                            goForward: ƒ goForward()
                            push: ƒ push(path, state)
                            replace: ƒ replace(path, state)
                location:
                            pathname: "/about"
                            search: ""
                            state: undefined
                match:
                            params: {
    
    }
                            path: "/about"
                            url: "/about"

十、10_src_封装NavLink

## 五、NavLink与封装NavLink
    1.NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
    2.标签体内容是一个特殊的标签属性
    3.通过this.props.children可以获取标签体内容

十一、11_src_Switch的使用

## 六、Switch的使用
    1.通常情况下,path和component是一一对应的关系。
    2.Switch可以提高路由匹配效率(单一匹配)

十二、12_src_解决样式丢失问题

## 七、解决多级路径刷新页面样式丢失的问题
    1.public/index.html 中 引入样式时不写 .// (常用)
    2.public/index.html 中 引入样式时不写 ./%PUBLIC_URL% (常用)
    3.使用HashRouter

十三、13_src_精准匹配与模糊匹配

## 八、路由的严格匹配与模糊匹配
    1.默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
    2.开启严格匹配:<Route exact={
    
    true} path="/about" component={
    
    About}/>
    3.严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由

十四、14_src_Redirect的使用

## 九、Redirect的使用	
    1.一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
    2.具体编码:
            <Switch>
                <Route path="/about" component={
    
    About}/>
                <Route path="/home" component={
    
    Home}/>
                <Redirect to="/about"/>
            </Switch>

十五、15_src_嵌套路由的使用

## 十、嵌套路由
    1.注册子路由时要写上父路由的path值
    2.路由的匹配是按照注册路由的顺序进行的

十六、16_src_向路由组件传递params参数

十七、17_src_向路由组件传递search参数

十八、18_src_向路由组件传递state参数

## 十一、向路由组件传递参数
1.params参数
            路由链接(携带参数)<Link to='/demo/test/tom/18'}>详情</Link>
            注册路由(声明接收)<Route path="/demo/test/:name/:age" component={
    
    Test}/>
            接收参数:this.props.match.params
2.search参数
            路由链接(携带参数)<Link to='/demo/test?name=tom&age=18'}>详情</Link>
            注册路由(无需声明,正常注册即可)<Route path="/demo/test" component={
    
    Test}/>
            接收参数:this.props.location.search
            备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
3.state参数
            路由链接(携带参数)<Link to={
    
    {
    
    pathname:'/demo/test',state:{
    
    name:'tom',age:18}}}>详情</Link>
            注册路由(无需声明,正常注册即可)<Route path="/demo/test" component={
    
    Test}/>
            接收参数:this.props.location.state
            备注:刷新也可以保留住参数

十九、19_src_push与replace模式

二十、20_src_编程式路由导航

## 十二、编程式路由导航
    借助this.prosp.history对象上的API对操作路由跳转、前进、后退
            -this.prosp.history.push()
            -this.prosp.history.replace()
            -this.prosp.history.goBack()
            -this.prosp.history.goForward()
            -this.prosp.history.go()

二十一、21_src_withRouter的使用

//withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
//withRouter的返回值是一个新组件

二十二、22_src_antd组件库的使用

## 十四、antd的按需引入+自定义主题
    1.安装依赖:yarn add react-app-rewired customize-cra babel-plugin-import less less-loader
    2.修改package.json
            ....
                "scripts": {
    
    
                    "start": "react-app-rewired start",
                    "build": "react-app-rewired build",
                    "test": "react-app-rewired test",
                    "eject": "react-scripts eject"
                },
            ....
    3.根目录下创建config-overrides.js
            //配置具体的修改规则
            const {
    
     override, fixBabelImports,addLessLoader} = require('customize-cra');
            module.exports = override(
                fixBabelImports('import', {
    
    
                    libraryName: 'antd',
                    libraryDirectory: 'es',
                    style: true,
                }),
                addLessLoader({
    
    
                    lessOptions:{
    
    
                        javascriptEnabled: true,
                        modifyVars: {
    
     '@primary-color': 'green' },
                    }
                }),
            );
        4.备注:不用在组件里亲自引入样式了,即:import 'antd/dist/antd.css'应该删掉

三、redux_test

一、1_src_纯react版

1.英文文档: https://redux.js.org/
2.中文文档: http://www.redux.org.cn/
3.Github: https://github.com/reactjs/redux

二、2_src_redux精简版

## 1.求和案例_redux精简版
(1).去除Count组件自身的状态
(2).src下建立:
        -redux
            -store.js
            -count_reducer.js

(3).store.js:
    1).引入redux中的createStore函数,创建一个store
    2).createStore调用时要传入一个为其服务的reducer
    3).记得暴露store对象

(4).count_reducer.js:
    1).reducer的本质是一个函数,接收:preState,action,返回加工后的状态
    2).reducer有两个作用:初始化状态,加工状态
    3).reducer被第一次调用时,是store自动触发的,
                    传递的preState是undefined,
                    传递的action是:{type:'@@REDUX/INIT_a.2.b.4}

(5).在index.js中监测store中状态的改变,一旦发生改变重新渲染<App/>
备注:redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。

三、3_src_redux完整版

## 2.求和案例_redux完整版
    新增文件:
        1.count_action.js 专门用于创建action对象
        2.constant.js 放置容易写错的type值

四、4_src_异步action版

## 3.求和案例_redux异步action版
 (1).明确:延迟的动作不想交给组件自身,想交给action
 (2).何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回。
 (3).具体编码:
            1).yarn add redux-thunk,并配置在store中
            2).创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务。
            3).异步任务有结果后,分发一个同步的action去真正操作数据。
 (4).备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action。

五、5_src_react-redux的基本使用

## 4.求和案例_react-redux基本使用
(1).明确两个概念:
    1).UI组件:不能使用任何redux的api,只负责页面的呈现、交互等。
    2).容器组件:负责和redux通信,将结果交给UI组件。
(2).如何创建一个容器组件————靠react-redux 的 connect函数
        connect(mapStateToProps,mapDispatchToProps)(UI组件)
            -mapStateToProps:映射状态,返回值是一个对象
            -mapDispatchToProps:映射操作状态的方法,返回值是一个对象
(3).备注1:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入
(4).备注2:mapDispatchToProps,也可以是一个对象

六、6_src_react-redux优化

## 5.求和案例_react-redux优化
(1).容器组件和UI组件整合一个文件
(2).无需自己给容器组件传递store,给<App/>包裹一个<Provider store={store}>即可。
(3).使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。
(4).mapDispatchToProps也可以简单的写成一个对象
(5).一个组件要和redux“打交道”要经过哪几步?
    (1).定义好UI组件---不暴露
    (2).引入connect生成一个容器组件,并暴露,写法如下:
            connect(
                state => ({key:value}), //映射状态
                {key:xxxxxAction} //映射操作状态的方法
            )(UI组件)
    (4).在UI组件中通过this.props.xxxxxxx读取和操作状态

七、7_src_react-redux_数据共享版

## 6.求和案例_react-redux数据共享版
(1).定义一个Pserson组件,和Count组件通过redux共享数据。
(2).为Person组件编写:reducer、action,配置constant常量。
(3).重点:Person的reducer和Count的Reducer要使用combineReducers进行合并,
        合并后的总状态是一个对象!!!
(4).交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。

八、8_src_react-redux_开发者工具

## 7.求和案例_react-redux开发者工具的使用
(1).yarn add redux-devtools-extension
(2).store中进行配置
        import {composeWithDevTools} from 'redux-devtools-extension'
        const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))

九、9_src_最终版

## 8.求和案例_react-redux最终版
(1).所有变量名字要规范,尽量触发对象的简写形式。
(2).reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer

四、小提示

#结构赋值
const {
    
    value} = this.selectNumber
#强制刷新页面(不走缓存)
shift+刷新
#安装插件ES7+ React/Redux/React-Native snippets
rcc/rfc(插件快速编程)

猜你喜欢

转载自blog.csdn.net/weixin_45207323/article/details/130983216
今日推荐