一、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="点击按钮提示数据" />
// 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="点击按钮提示数据" />
<button onClick={
this.showData}>点我提示左侧的数据</button>
<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="点击按钮提示数据" /> */}
<input ref={
(currentNode) => {
this.input1 = currentNode; }} type="text" placeholder="点击按钮提示数据" />
<button onClick={
this.showData}>点我提示左侧的数据</button>
<input onBlur={
this.showData2} ref={
c => this.input2 = c} type="text" placeholder="失去焦点提示数据" />
</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="点击按钮提示数据" />
<button onClick={
this.showData}>点我提示左侧的数据</button>
<input onBlur={
this.showData2} ref={
this.myRef2} type="text" placeholder="失去焦点提示数据" />
</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="点击按钮提示数据"/>
<button onClick={
this.showData}>点我提示左侧的数据</button>
<input onBlur={
this.showData2} type="text" placeholder="失去焦点提示数据"/>
</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生命周期(旧)图
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生命周期(新)图
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版本号))
重新全局安装和创建项目
成功显示
扫描二维码关注公众号,回复:
15429592 查看本文章
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(插件快速编程)