概述
之前,学习过React,但是2、3个月没用的话,就是忘得差不多了,在最近的这段时间里发现大厂用React技术栈很多,然后就特意去温习了一下,整个感觉就是React挺吃JS的,国庆期间然后卷了一波,成为他们口中所说的“卷王!”
React全家桶
一、初识React
首先需要引入React库,react.development.js
需要在react-dom.development.js
之前引入,因为react.development.js
是核心库。
二、jsx的语法编写规则
- 定义虚拟DOM时,不要写引号
- 标签中混入JS表达式要用
{}
包起来 - 标签内样式的类名指定不能使用
class
,得用className
- 在标签内写内联样式,要用
style={{color:'red',fontSize:'12px'}}
形式去写 - 虚拟DOM只有一个根标签
- 所有的标签必须闭合
- 标签的首字母
- 若小写字母开头,则将该标签转为html中同名的元素。没有同名元素会报错
- 若大写字母开头,React就会去渲染对应的组件。如果组件没有定义,则就会去报错
如果想要写判断条件,可以写成三元表达式,三元表达式可以嵌套使用
2.1 区分js语句代码与js表达式
表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方,下面这些都是表达式
a
a+b
main()
arr.map()
function test(){}
语句代码:下面这些都是语句代码
if(){}
for(){}
switch(){}
三、React中的组件
3.1 函数式组件
3.2 类式组件
3.3 组件实例的三大核心属性
3.3.1 state
- state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)
- 通过更新组件的state来更新对应的页面显示(重新渲染组件)
注:
1. 组件中render方法中的this为组件实例对象
2. 组件自定义方法中的this为undefined,如何解决?
- 强制绑定this:通过函数对象的bind()
- 使用箭头函数
3. 状态数据,不能直接修改,得通过setState来对数据进行更新
state的基本使用
state的简写方式如下:
类组件中在创建之后发生了什么?
- 首先需要在类组件内部直接初始化state的状态
- 接着在
render()
函数内部定义常量,拿到state中的数据后,return
出需要展示的内容 - 在该类组件内部可以自定义许多方法,但是为了使方法挂载到该类的实例上,需要用
赋值语句+箭头函数的形式
来自定义方法,从而避免this指向丢失的问题
最后,采用ReactDOM.render()
的方式,将组件渲染到页面上。
3.3.2 props
- props是每个组件对象都会有的属性
- 组件标签的所有属性都保存在props中
作用:
- 通过标签属性从组件外向组件内传递变化的数据
- 组件内部不要修改props数据
props的基本使用
对props进行限制
在脚手架对props进行限制时,首先需要npm i prop-types
,然后在子组件中引入,
然后需要用static关键字声明,之后对其接收到的数据进行限制
<!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>Document</title>
</head>
<body>
<!-- 准备容器 -->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!-- 引入React核心库 -->
<script src="../../00-React库/react.development.js"></script>
<!-- 引入React.dom库 -->
<script src="../../00-React库/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../../00-React库/babel.min.js"></script>
<!-- 引入prop-type,来对props进行限制 -->
<script src="../../00-React库/prop-types.js"></script>
<!-- 需求 -->
<!--
将要展示的年龄在原来的基础上+1
姓名限制为必填
性别限制为字符串
年龄限制为数字
-->
<script type="text/babel">
// 创建组件
class Person extends React.Component{
render(){
console.log(this)
const {name,age,sex} = this.props
// props是只读的,不可以修改
// this.props.name = 'aaa' 此行代码会报错
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age+1}</li>
<li>性别:{sex}</li>
</ul>
)
}
}
// 对标签属性进行类型、必要性的限制
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name为必传项,且为字符串
age:PropTypes.number, //限制age为数字
sex:PropTypes.string, //限制sex为字符串
speak:PropTypes.func, //限制speak为函数
}
// 指定属性的默认值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
// 渲染组件
ReactDOM.render(<Person name="李白" age={18} sex="男"/>,document.getElementById('test1'))
ReactDOM.render(<Person name='杜甫' sex="男"/>,document.getElementById('test2'))
// ReactDOM.render(<Person name="貂蝉" age="90" sex="女"/>,document.getElementById('test3'))
// 批量传递props
const p = {name:'宋庆扬',age:20,sex:'女'}
ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
function speak() {
console.log('我说话了')
}
</script>
</body>
</html>
props的简写方式
在该类组件的内部,在需要添加的属性前面加上static
关键字,即可给类自身添加属性
<!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>Document</title>
</head>
<body>
<!-- 准备容器 -->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!-- 引入React核心库 -->
<script src="../../00-React库/react.development.js"></script>
<!-- 引入React.dom库 -->
<script src="../../00-React库/react-dom.development.js"></script>
<!-- 引入babel -->
<script src="../../00-React库/babel.min.js"></script>
<!-- 引入prop-type,来对props进行限制 -->
<script src="../../00-React库/prop-types.js"></script>
<!-- 需求 -->
<!--
将要展示的年龄在原来的基础上+1
姓名限制为必填
性别限制为字符串
年龄限制为数字
-->
<script type="text/babel">
// 创建组件
class Person extends React.Component {
// 对标签属性进行类型、必要性的限制
static propTypes = {
name: PropTypes.string.isRequired, //限制name为必传项,且为字符串
age: PropTypes.number, //限制age为数字
sex: PropTypes.string, //限制sex为字符串
speak: PropTypes.func, //限制speak为函数
}
// 指定属性的默认值
static defaultProps = {
sex: '男',//sex默认值为男
age: 18 //age默认值为18
}
render() {
console.log(this)
const { name, age, sex } = this.props
// props是只读的,不可以修改
// this.props.name = 'aaa' 此行代码会报错
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age + 1}</li>
<li>性别:{sex}</li>
</ul>
)
}
}
// 渲染组件
ReactDOM.render(<Person name="李白" age={18} sex="男" speak={speak} />, document.getElementById('test1'))
ReactDOM.render(<Person name='杜甫' sex="男" />, document.getElementById('test2'))
// ReactDOM.render(<Person name="貂蝉" age="90" sex="女"/>,document.getElementById('test3'))
// 批量传递props
const p = { name: '宋庆扬', age: 20, sex: '女' }
ReactDOM.render(<Person {...p} />, document.getElementById('test3'))
function speak() {
console.log('我说话了')
}
</script>
</body>
</html>
3.3.3 refs与事件处理
理解:组件内的标签可以定义ref属性来标识自己
字符串形式的ref
回调的ref
ref直接接收一个回调,该回调的参数就是该元素的节点,随后起一个常量名用来接收该节点。
ref回调次数的问题
ref方式数的方式定义的,在更新的过程中它会被执行两次,第一次传入的参数为null,第二次传入的参数才是dom元素。这是因为在每次渲染时会创建一个新的函数实例,React会清空旧的ref然后再设置一个新的。
解决方案
将ref的回调函数定义成一个class的绑定函数的方式可以避免以上问题,但是写成内联函数的方式也无关紧要
创建Ref容器
this.ref2.current
指代的就是当前ref2所指向的根节点
ref中的事件处理
- 通过onXxx属性指定事件处理函数(注意大小写)
- React使用的是自定义(合成)事件,而不是使用的原生DOM事件—–为了更好的兼容性
- React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)—–为了更加高效
- 通过event.target得到发生事件的DOM元素对象—–不要过度使用ref
- 即使在某一个根元素中不传入ref,也可以发生回调事件,前提是只能发生在某个根节点上的自身的事件
四、React如何将输入的值同步更新到状态中
首先输入类的DOM标签中都包含着一个onChage回调
,然后可以在这个回调中使用setState()
来改变state中的数据,与Vue数据双向绑定原理类似
<body>
<script src="../../00-React库/react.development.js"></script>
<script src="../../00-React库/react-dom.development.js"></script>
<script src="../../00-React库/babel.min.js"></script>
<script src="../../00-React库/prop-types.js"></script>
<div id="box"></div>
<script type="text/babel">
// 1. 创建组件
class Login extends React.Component {
state = {
username:'',
password:''
}
submit = (event)=>{
event.preventDefault();
const {username,password} = this.state
alert(`您输入的用户名是${ username},密码是${ password}`)
}
// 保存用户名到状态中
saveUsername = (event)=>{
this.setState({
username:event.target.value
})
}
// 保存密码到状态中
savePassword = (event)=>{
this.setState({
password:event.target.value
})
}
render() {
return (
<form onSubmit={this.submit}>
用户名:<input type="text" onChange={this.saveUsername} name="username" />
密码:<input type="text" onChange={this.savePassword} name="password" />
<button>提交</button>
</form>
)
}
}
// 2. 渲染组件
ReactDOM.render(<Login/>,document.getElementById('box'))
</script>
</body>
五、React生命周期
旧的生命周期