📑前言
本文主要是【React】——React基础的文章,如果有什么需要改进的地方还请大佬指出⛺️
🎬作者简介:大家好,我是听风与他🥇
☁️博客首页:CSDN主页听风与他
🌄每日一句:狠狠沉淀,顶峰相见
目录
- 📑前言
- React学习
- 1.react特点
- 1.1 ReactDOM
- 1.2 jsx的基本语法
- 1.3 js遍历数组
- 1.4 组件的使用
- 1.5 类式组件
- 2.组件实例三大属性
- 1.state
- 2.pros
- 3.refs
- 3.react中收集表单数据
- 1.非受控组件
- 2.受控组件
- 4.react的生命周期
- 1.Demo
- 2.DOM的diffing算法
- 3.经典面试题
- 📑文章末尾
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.statereturn <h1 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h1>}changeWeather = ()=>{const isHot = this.state.isHotthis.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.propsreturn (<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} = propsreturn (<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.refsalert(input1.value)}show2 = () =>{const {input2}=this.refsalert(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.refsalert(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}=thisalert(`你输入的用户名是:${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.statealert(`用户名为${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.stateopacity-=0.1if(opacity<=0) opacity=1this.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.stateconst 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>