React
官网:https://react.docschina.org
facebook开发的一套开源框架
react是构建用户界面的js库
jq是函数库,主要用于界面的dom操作
优势
-
声明式定义主键:使用class|function关键字来定义react组件
-
使创建交互式UI变得轻而易举,交互式UI,交互式是用户的一种行为,ui页面(让用户在界面上的行为变得轻而易举)
-
组件化开发:让项目容易维护。复用率增强,提高开发效率。组件和组件之间是互不干扰的个体
-
一次学习,随处编写
-
工作高效
内部使用的是虚拟dom,虚拟dom不能被界面渲染的dom,跟js的dom对象结构很像,其实就是js的dom对象的副本。虚拟dom和真实dom对比采用的是diff算法。
虚拟dom和真实的dom之间是 映射关系,当我们的虚拟dom发生改变时,真实的dom也会跟着改变。最大的优势就是该更新的更新,不更新就不更新,这种渲染方式叫最小渲染,大大降低了前段页面的重构。
spa单页面应用和mpa多页面应用
s单页面应用
有点:不需要频繁向服务器请求页面
缺点:没有页面,数据没有单独的页面,都是ajax请求过来的,该页面不容易被百度搜索
mpa多页面应用
优点:便于百度搜索
缺点:请求量大
一个链接对应一个页面
jsx学习
react组件化开发,开发组件的过程中采用jsx语法
jsx语法
结构上跟html很像,但是本质还是js语言
babel工具 编译jsx语法
babel官网:http://www.babeljs.cn/
//jsx编译之前
<div class="app">hello word</div>
//jsx编译之后
React.createElement("div",{
class:"app"
},"hello word");//返回结果就是虚拟dom
代码部分
babel-cli是babel的一个脚手架工具
配置编译jsx的流程
1、创建babel/config.js|babelrc
2、项目初始化npm init -y 生成一个package.json文件
3、下载babel脚手架 @babel/cli npm install --save-dev @babel/cli(提供编译指令)和@babel/core(提供编译代码)
1、babel脚手架的使用指令
2、将a.js编译成b.js npx babel a.js -o b.js
3、npm install --save-dev @babel/preset-react 告诉babel编译的语法是react
4、在babelrc中添加我们的配置项
{"presets":["@babel/preset-react"]}
5、最后执行npx babel a.js -o b.js
4、配置.babelrc
React安装
- npm操作
- package.jaon配置项
CDN链接
<script crossorigin src="https://unpkg.com/react@16/umd/reacrt.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>//将html编译成jsx
React提供相关的api
React-dom提供操作浏览器DOM的方法
ReactDOM.render()将jsx组件渲染到指定的节点容器,有两个参数,第一个参数是jsx组件,第二个参数是节点对象(document来获取)
注意:在script标签上要添加type属性:text/babel
<script type="text/babel">
var html1=<div>hello word</div>;//jsx
ReactDOM.render(html1,document.getElementById("app"));
</script>
React.createElement()
React.createElement()是jsx语法编译的结果,这个函数的返回值是一个虚拟DOM
<script type="text/babel">
var html1=React.createElement("h1",null,"hello curry");
ReactDOM.render(html1,document.getElementById("app"));
</script>
babel官网可以将html语法编译成jsx
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x3hG8iQY-1614582601193)(D:\MyNote.~typoraJs.assets\image-20210222204249929.png)]
定义组件
类组件-class 函数组件-function
-
组件首字母必须大写,这是react用于区分组件和普通标签的方法
-
组件中返回的jsx代码必须有一个顶层标签
类组件
class Person extends React.component{
render(){
return <div>hello word</div>
}
}
//渲染
ReactDOM.render(<Person/>,document.getElementById("app"))
函数组件
function Person(){
return <div>hello web</div>
}
ReactDOM.render(<Person/>,document.getElementById("app"))
组件嵌套
父组件嵌套一个子组件
组件当标签使用的时候,必须是闭合标签。
或
<script type="text/babel">
class son extends React.Component{
render(){
return <div><p>这是子组件</p></div>
}
}
class Father extends React.Component{
render(){
return <div><h3>这是父组件</h3><Son></Son></div>
//或者写成<div><h3>这是父组件</h3><Son/></div>
}
}
ReactDOM.render(<Father/>,document.getElementById("app"))
</script>
jsx语言
1、表达式
jsx是js 的拓展语言,本质还是js
使用jsx中的表达式,需要写在{}中
jsx本身也是一个表达式
无论是如
//jsx表达式
var name="zhangsan"
var html=<div>hello curry</div>
//在render中调用直接return html即可
class Father extends React.Component{
render(){
return <div><h3>{name}</h3></div>
}
}
ReactDOM.render(<Father/>,document.getElementById("app"))
2、属性
3、类名className
sx中不能使用class给元素添加类名,jsx本身也是js,在js中class是关键字,要使用className给元素添加类名
var div='div1'
class Father extendsReact.Component{
render(){
return <div id={div} className="div2">hello howie</div>
}
}
ReactDOM.render(<Father/>,document.getElementById("app"))
4、jsx表达式 数组自动展开
var arrs=[<p key="1">zhangsan</p>,<p key="2">python</p>,<p key="3">php</p>]
class Father extends React.component{
render(){
return <div classNmae="div2">{arrs}</div>
}
}
ReactDOM,render(<Father/>,document.getElementById("app"))
5、三元运算
var b1=true
class Father extends React.Component{
render(){
//法1
return <div className="div2">{b1?<h3>hello word</h3>:null}</div>
//法2
return <div className="div2">{b1&&<h3>hello</h3>}</div>
}
}
6、jsx的循环
使用map方法,不要使用for循环
//jsx表达式 循环
var arrs=[{id:1,name:"curry",age:20},{id:2,name:"curry",age:20},{id:3,name:"curry",age:20}]
class Person extends React.Component{
render(){
return <div>
<ul>
{
arrs.map(function(p,index){
return <li key={index}> {p.name},{p.age} </li>
})
}
</ul>
</div>
}
}
ReactDOM,render(<Person/>,document.getElementById("app"))
for循环
<script type="text/babel">
class Hello extends React.Component {
render(){
var list = (length) => {
var res = [];
for(var i = 0; i < length; i++) {
res.push(<h2 key={i}>hello react</h2>)
}
return res
}
return (
<div>hello {list(this.props.length)}
</div>
)
}
}
var helloData = 5
ReactDOM.render(
<Hello length = {helloData}/>,
document.getElementById('root')
);
7、事件
on+事件名 给组件标签添加事件
- 事件名 首字母必须大写
- 类组件中的jsx中的this指向组件实例对象
//在class外的function函数
function sayHello(){
console.log("Hello")
}
//在class内部的function函数
class Person extends React.Component{
sayGoodbye(){
console.log("Goodbye")
}
render(){
return <div>
<button onClick={sayHello}>点击Hello</button>
<button onClick={this.sayGoodbye}>点击Hello</button>
</div>
}
}
ReactDOM.render(<Person/>,document.getElementById("app"))
8、函数传参
-
默认传递一个参数是事件对象
传递参数的方法一
class Person extends React.Component{
fn(e,event){
//输出hello
console.log(e)
//输出事件对象
console.log(event)
}
render(){
console.log(this)
return <div>
//传递参数方法一
<button onClick={(e)=>{this.fn("hello",e)}}>点击 </button>
</div>
}
}
传递参数方法二
<button onClick={this.函数名.bind(null,"word")}>按钮</button>
9、props
我们在使用组件的时候可以向组件传递数据,在组件可以使用props这个对象来调用数据
- props在组件内部只是可读的,不能被修改
- 如果props的数据源被修改,在组件被得到的props数据也会随着修改(数据驱动DOM)
类组件
class Person extends React.Component{
render(){
return <div>
<p>hello</p>
//输出curry
<p>{this.props.name}</p>
</div>
}
}
//name="curry自动添加到props属性中
ReactDOM.render(<Persom name="curry"/>,
document.getElementById("app"))
函数组件
function Person(props){
console.log(props)
return <div>
<p>{props.name}</p>
</div>
}
ReactDOM.render(<Person name="curry"/>,
document.getElementById("app"))
设置props初始值
类组件
class Person extends React.Component{
//初始化props
static defaultProps={
name:"curry"
}
render(){
console.log(this)
return <div>
//输出curry
<p>{this.props.name}</p>
</div>
}
}
ReactDOM.render(<Person/>,document/getElementById("app"))
函数组件
function Person(props){
return <div>
<p>{props.name}</p>
</div>
}
//初始化props
Person.defaultProps={
name:"curry"
}
ReactDOM.render(<Person/>,document/getElementById("app"))
props.children
props.children就是我们在调用组件时填充在组件标签里面的内容。
class Person extends React.Component{
render(){
console.log(this)
return
<p>{this.props.children}</p>
}
}
ReactDOM.render(<Person name="curry"><h1>我是peops.children<h1></Person>,document.getElementById("app"))
props的注意事项
- props用于传递数据,这个数据是一个单向传递,从根节点组件向它的子孙组件传递,逆向传递是不被允许的
- 子孙组件如果想修改根节点组件的状态,则需要根节点组件给子孙组件传递事件方法
事件函数传递
事件函数中的this问题
- 事件函数中的this不是我们组件实例对象,而是undefined
- 在构造器constructor里我们需要对事件函数进行this绑定,否则函数中的this都是undefined
//子组件
class Person extends React.Component{
constructor(){
super()
this.click=this.click.bind(this)
}
click(){
this.props.onma()
}
render(){
return <div>
<button onClick={this.click}>事件点击</button>
</div>
}
}
//根节点组件
class App extends React.Component{
fn(){
console.log("我来自父组件")
}
render(){
return <div>
<Person onma={this.fn}></Person>
</div>
}
}
ReactDOM.render(<App/>,document.getElementById("app"))
state
state是组件自身的一个状态,组件内部自己的数据
组件的加载流程(组件的生命周期函数)
首先执行组件的构造器constructor()处理组件内部的状态
其次执行render()得到一个虚拟DOM
最后执行componentDidMount()插入我们真是DOM
类组件
class App extends React.Component{
constructor(){
super()
//添加state状态
this.state={
name:"curry"
}
}
render(){
return <div>
<span>{this.state.name}</span>
</div>
}
}
ReactDOM.render(<App/>,document.getElementById("app"))
函数组件不能直接添加state属性,要使用后面的Hooks知识点。
state注意
- state是组件内部的数据状态
- 读取state状态直接使用this.state
- 更改state需要使用setState
class App extends React.Component{
constructor(){
super()
//添加state状态
this.state={
name:"curry"
}
//事件函数中的this绑定
this.click=this.click.bind(this)
}
click(){
//this放心食用
this.setSate({
name:"Howie"
})
}
render(){
return <div>
<span>{this.state.name}</span>
//添加一个按钮调用click函数来更改state.name
<button onClick={this.click}>点击更改state</button>
</div>
}
}
ReactDOM.render(<App/>,document.getElementById("app"))
数据双向绑定
组件内部的state状态发生改变,更新我们视图中元素的状态,视图中元素的状态发生改变也会影响组件中state的状态。
input表单演示数据双向绑定
class App extends React.Component{
constructor(){
super()
//添加state状态
this.state={
name:"curry"
}
//绑定this
this.changed=this.changed.bind(this)
}
changed(event){
this.setState({
name:event.target.value
})
}
render(){
reutrn <div>
<span>{this.state.name}</span>
<div>
<input type="text" onChange={this.changed} value={this.state.name}/>
</div>
</div>
}
}
ReacrDOM,render(<App/>,document.getElementById("app"))
组件生命周期
生命周期就是组件加载的一个流程
- 初始化组件
- 渲染组件
- 更新组件
- 删除组件
研究组件的声明周期
-
mounting家在组建
-
constructor()构造器函数 初始化数据状态 比如state
-
render() 返回一个Virtual DOM
-
componentDidMount() DOM节点插入之后调用的声明函数
-
可以做网络请求
-
setState()更改数据状态
class App extends React.Component{ constructor(){ super() this.state={ name:"curry" } console.log("组件初始化") } render(){ console.los("render") return <div> <p>{this.state.name}</p> </div> } componentDidMount(){ console.log("组件插入之后") } } ReactDOM,render(<App/>,document.getElementById("app"))
-
-
-
updating更新组件 当状态数据(props或state)发生变化的时候会触发
-
再次执行render函数
-
componentDidUpdate()数据状态更新之后会调用
-
可以做DOM操作
-
网络请求(如,当props未发生变化时,则不会执行网络请求)
componentDidUpdate(prevProps){ //典型用法(不要忘记比较props) if(this,props,userID!=precProps.userID){ this,fetchData(this.props.userID); } }
-
setState()
-
-
-
unmounting卸载组件
-
componentWillUnmount()组件卸载之前会调用这个方法
-
componentWillUnmount()会在组件卸载以及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除timer,取消网络请求或清除在componentDidMount()中创建的订阅等。
-
ReactDOM.unmountComponentAtNode(container)
-
用于卸载我们的组件
-
参数就是我们插入组件的容器,dom对象,这个dom对象就是我们document.getElementById()获取的根节点
-
-
//组件卸载之前会调用的方法
componentWillUnmount(){
}
render(){
return <div>
<button onClick={()=>(ReactDOM.unmoutComponentAtNode(document.getElementById("app")))}>卸载组件</button>
</div>
}
记比较props)
if(this,props,userID!=precProps.userID){
this,fetchData(this.props.userID);
}
}
```
- setState()
-
unmounting卸载组件
-
componentWillUnmount()组件卸载之前会调用这个方法
-
componentWillUnmount()会在组件卸载以及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除timer,取消网络请求或清除在componentDidMount()中创建的订阅等。
-
ReactDOM.unmountComponentAtNode(container)
-
用于卸载我们的组件
-
参数就是我们插入组件的容器,dom对象,这个dom对象就是我们document.getElementById()获取的根节点
-
-
//组件卸载之前会调用的方法
componentWillUnmount(){
}
render(){
return <div>
<button onClick={()=>(ReactDOM.unmoutComponentAtNode(document.getElementById("app")))}>卸载组件</button>
</div>
}