📑前言
本文主要是【React】——React基础的文章,如果有什么需要改进的地方还请大佬指出⛺️
🎬作者简介:大家好,我是听风与他🥇
☁️博客首页:CSDN主页听风与他
🌄每日一句:狠狠沉淀,顶峰相见
目录
React学习
1.react特点
- 1.采用组件化的模式,声明式编程,提高开发效率及组件复用率
- 2.使用虚拟DOM+优秀的
Diffing
算法,尽量减少与真实DOM的交互
1.1 ReactDOM
- ReactDOM将组件或JSX元素渲染到DOM中。render(),负责在浏览器中渲染应用程序。
- render方法只会覆盖,不会追加。
1.2 jsx的基本语法
-
1.定义虚拟DOM,不能使用
""
-
2.标签中混入JS表达式时使用
{}
id = {myId.toUpperCase()}
-
3.样式的类名指定不能使用class,使用
className
-
4.内敛样式要使用
{{}}
包裹style={{color:'skyblue',fontSize:'24px'}}
1.3 js遍历数组
objArr.map((item, index) => {
return item.name
})
1.4 组件的使用
当应用是以多组件的方式实现,这个应用技术一个组件化的应用
- 1.组件名必须是首字母大写
- 虚拟DOM元素只能有一个根元素
- 3.虚拟DOM元素必须有结束标签
</>
渲染类组件标签的基本流程
- 1.React内部会创建组件实例对象
- 调用
render()
得到虚拟DOM,并解析为真实DOM - 插入到指定的页面元素内部
1.5 类式组件
class MyComponent extends React.Component {
state = {isHot:false}
render() {
const {isHot} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h1>
}
changeWeather = ()=>{
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
}
ReactDOM.render(<MyComponent/>,document.querySelector('.test'))
this
的指向真的需要好好学习
- 组件中的 render 方法中的 this 为组件实例对象
- 组件自定义方法中由于开启了严格模式,this 指向undefined如何解决
- 通过 bind 改变 this 指向
- 推荐采用箭头函数,箭头函数的
this
指向
- state 数据不能直接修改或者更新
2.组件实例三大属性
1.state
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
简单的说就是组件的状态,也就是该组件所存储的数据
类式组件中的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<div id="zzl"></div>
<script type="text/babel">
class Weather1 extends React.Component{
constructor(props){
super(props)
}
state = {
weather:'炎热'
}
render(){
return <h1>今天的天气很{this.state.weather}</h1>
}
}
ReactDOM.render(<Weather1/>,document.getElementById('zzl'))
</script>
</body>
</html>
2.pros
与state
不同,state
是组件自身的状态,而props
则是外部传入的数据
类式组件使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<div id="zz"></div>
<script type="text/babel">
class Person extends React.Component{
render(){
return (
<ul>
{/* 接受数据并显示*/}
<li>{this.props.name}</li>
<li>{this.props.age}</li>
<li>{this.props.sex}</li>
</ul>
)
}
}
ReactDOM.render(<Person name="zzl" age="19" sex="男" />,document.getElementById('zz'))
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<div id="zz"></div>
<script type="text/babel">
class Person extends React.Component{
render(){
const {name,age,sex} = this.props
return (
<ul>
{/* 接受数据并显示*/}
<li>{this.props.name}</li>
<li>{this.props.age}</li>
<li>{this.props.sex}</li>
</ul>
)
}
}
const p = {name:"zzl",age:"18",sex:'男'}
ReactDOM.render(<Person {...p} />,document.getElementById('zz'))
</script>
</body>
</html>
函数式组件中的使用
函数在使用props的时候,是作为参数进行使用的(props)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<script type="text/javascript" src="/js/prop-types.js"></script>
<div id="zzl"></div>
<script type="text/babel">
const p = {name:"zzl",age:"18",sex:'男'}
function Person(props){
const {name,age,sex} = props
return (
<ul>
<li>{name}</li>
<li>{age}</li>
<li>{sex}</li>
</ul>
)
}
ReactDOM.render(<Person {...p} />,document.getElementById('zzl'))
</script>
</body>
</html>
函数组件的 props
定义:
- 在组件标签中传递
props
的值 - 组件函数的参数为
props
- 对
props
的限制和默认值同样设置在原型对象上
3.refs
Refs 提供了一种方式,允许我们访问 DOM 节点或在 render
方法中创建的 React 元素。
在我们正常的操作节点时,需要采用DOM API 来查找元素,但是这样违背了 React 的理念,因此有了
refs
字符串形式
在react,Vue中,均可以使用ref来操作DOM
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<script type="text/javascript" src="/js/prop-types.js"></script>
<div id="zzl"></div>
<script type="text/babel">
class Demo1 extends React.Component{
show1=()=> {
const {input1}=this.refs
alert(input1.value)
}
show2 = () =>{
const {input2}=this.refs
alert(input2.value)
}
render(){
return (
<div>
<input ref="input1" type="text" placeholder="点击按钮提示数据" />
<button onClick={this.show1}>点击按键</button>
<input onBlur={this.show2} ref="input2" type="text" placeholder="失去焦点提示数据" />
</div>
)
}
}
ReactDOM.render(<Demo1/>,document.getElementById('zzl'))
</script>
</body>
</html>
createRef创建ref容器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<script type="text/javascript" src="/js/prop-types.js"></script>
<div id="zzl"></div>
<script type="text/babel">
class Demo1 extends React.Component{
// React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是专人专用的
myRef = React.createRef()
show1=()=> {
alert(this.myRef.current.value);
}
show2 = () =>{
const {input2}=this.refs
alert(input2.value)
}
render(){
return (
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
<button onClick={this.show1}>点击按键</button>
<input onBlur={this.show2} ref="input2" type="text" placeholder="失去焦点提示数据" />
</div>
)
}
}
ReactDOM.render(<Demo1/>,document.getElementById('zzl'))
</script>
</body>
</html>
ref回调形式
ref={c=> this.username = c}
3.react中收集表单数据
1.非受控组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<script type="text/javascript" src="/js/prop-types.js"></script>
<div id="zzl"></div>
<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 onSubmit={this.handleSubmit}>
用户名:<input ref={c=> this.username = c} name="username" type="text"/>
密码:<input ref={c=> this.password = c} name="password" type="password"/>
<button>登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('zzl'))
</script>
</body>
</html>
2.受控组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<script type="text/javascript" src="/js/prop-types.js"></script>
<div id="zzl"></div>
<script type="text/babel">
class Login1 extends React.Component{
handleSubmit = (event) =>{
event.preventDefault()
const {username,password} = this.state
alert(`用户名为${username},密码为${password}`)
}
//初始化状态
state = {
username:'',
password:''
}
//保持用户名
saveUsername = (event)=>{
this.setState({username:event.target.value})
}
savePassword = (event)=>{
this.setState({password:event.target.value})
}
render(){
return (
<form onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveUsername} type="text" name="username" />
密码:<input onChange={this.savePassword} type="password" name="password"/>
<button>登录</button>
</form>
)
}
}
ReactDOM.render(<Login1/>,document.getElementById('zzl'))
</script>
</body>
</html>
4.react的生命周期
mount 挂载
unmount 卸载
记住,const声明的变量不能再改了
opacity可设置透明度,通过设置透明度可以实现由浅入深,由深入浅的效果。
组件挂载完毕
componentDidMount()
组件将要卸载
componentWillUnmount()
设置一个定时器
this.timer = setInterval(()=>{
},200);
卸载组件
ReactDOM.unmountComponentAtNode()
初始化渲染、状态更新之后
render()
1.Demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<script type="text/javascript" src="/js/prop-types.js"></script>
<div id="zzl"></div>
<script type="text/babel">
class Life1 extends React.Component{
state={
opacity:1
}
death = () =>{
ReactDOM.unmountComponentAtNode(document.getElementById('zzl'))
}
//挂载时
componentDidMount(){
this.timer = setInterval(()=>{
//获取原状态
let {opacity} = this.state
opacity-=0.1
if(opacity<=0) opacity=1
this.setState({opacity})
},200);
}
//组件将要卸载时
componentWillUnmount(){
clearInterval(this.timer)
}
render(){
return (
<div>
<h2 style={{opacity:this.state.opacity}}>学习react</h2>
<button onClick={this.death}>消失</button>
</div>
)
}
}
ReactDOM.render(<Life1/>,document.getElementById('zzl'))
</script>
</body>
</html>
效果
初始化阶段总结
执行顺序 constructor
-> getDerivedStateFromProps
或者 componentWillMount
-> render
-> componentDidMount
更新阶段
2.DOM的diffing算法
以按秒记时的时间为例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<script type="text/javascript" src="/js/prop-types.js"></script>
<div id="zzl"></div>
<script type="text/babel">
class Time1 extends React.Component{
state = {date:new Date()}
componentDidMount(){
setInterval(()=>{
this.setState({date:new Date()})
},1000)
}
render(){
return (
<div>
<input type="text"/>
<span>时间是{this.state.date.toTimeString()}</span>
</div>
)
}
}
ReactDOM.render(<Time1/>,document.getElementById('zzl'))
</script>
</body>
</html>
3.经典面试题
-
react/vue中的key有什么作用?(key的内部原理是什么?)
-
为什么遍历列表时,key最好不要用index?
-
1.简单来说,key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。
-
在状态中的数据发生变化,react会根据
新数据
生成新的虚拟DOM
,随后React进行新虚拟DOM
与旧虚拟DOM
的diff比较比较规则:
a.旧虚拟DOM中找到了与新虚拟DOM相同的key:
1.若虚拟DOM中内容没变,直接使用之前的真实DOM
2.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
b.旧虚拟DOM中未找到与新虚拟DOM相同的key,则会根据数据创建新的真实DOM,随后渲染到页面
-
-
1.若对数据进行:逆序添加、逆序删除等破坏顺序操作。
会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低。
2.如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
-
-
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>react</title>
</head>
<body>
<script type="text/javascript" src="/js/react.development.js"></script>
<script type="text/javascript" src="/js/react-dom.development.js"></script>
<script type="text/javascript" src="/js/babel.min.js"></script>
<script type="text/javascript" src="/js/prop-types.js"></script>
<div id="zzl"></div>
<script type="text/babel">
/*
慢动作回放----使用index索引值做为key
初始数据:
{id:1,name:'小张',age:18}
{id:2,name:'小李',age:18}
初始的虚拟DOM:
<li key=0>小张---18</li>
<li key=1>小李---19</li>
更新后的数据:
{id:3,name:'小王',age:18}
{id:1,name:'小张',age:18}
{id:2,name:'小李',age:18}
更新数据后的虚拟DOM:
<li key=0>小王---20</li>
<li key=1>小张---20</li>
<li key=2>小李---20</li>
--------------------------------------------------------
慢动作回放----使用id索引值做为key
初始数据:
{id:1,name:'小张',age:18}
{id:2,name:'小李',age:18}
初始的虚拟DOM:
<li key=1>小张---18</li>
<li key=2>小李---19</li>
更新后的数据:
{id:3,name:'小王',age:18}
{id:1,name:'小张',age:18}
{id:2,name:'小张',age:18}
更新数据后的虚拟DOM:
<li key=3>小王---20</li>
<li key=1>小张---20</li>
<li key=2>小李---20</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:[...persons,p]})
}
render(){
return (
<div>
<h2>展示人员信息</h2>
<button onClick={this.add}>添加一个小王</button>
<ul>
{
this.state.persons.map((personObj,index)=>{
return <li key={index}>{personObj.name}---{personObj.age}</li>
})
}
</ul>
<hr/>
<ul>
{
this.state.persons.map((personObj)=>{
return <li key={personObj.id}>{personObj.name}---{personObj.age}</li>
})
}
</ul>
</div>
)
}
}
ReactDOM.render(<Person/>,document.getElementById('zzl'))
</script>
</body>
</html>