@TOC

组件化方面

1.模块化:是从代码的角度来进行分析的,把一些可复用的代码,抽离为单个的模块;便于项目的开发与维护
2.组件化:是从UI界面的角度来进行分析,把一些可以复用的UI元素,抽离为单独的组件,便于项目的开发与维护
3.React是如何实现组件化的:React中有组件化概念,但是,并不是像Vue这样的组件模版文件,在React中,一切都是以JS来表现的。

React中的几个核心的概念

虚拟DOM

DOM和虚拟DOM的区别:

  • DOM:浏览器中,提供的概念;用JS对象,表示页面上的元素,并提供操作元素的API
  • 虚拟DOM:是框架中的概念;开发框架中的程序员手动用JS对象来模拟DOM元素和嵌套关系;

    本质:用js对象来模拟DOM元素和嵌套关系;
    目的:就是为了实现页面元素的高效更新;

    Diff算法

  • tree diff:新旧两颗DOM树,逐层对比的过程,就是Tree Diff,当整颗DOM逐层对比完毕,则所有需要按需更新的元素,必然能够找到;
  • componet diif:在进行Tree Diff 的时候,每一层中,组件级别的对比,叫做Component Diff;
  • 如果对比前后,组件的类型相同,则暂认为此组件不需要更新
  • 如果对比后,组件类型不同,则需要移除旧组件,创建新组件,并追加到页面上
  • element diff:在进行组件对比的时候,如果两个组件类型相同,则需要进行元素级别的对比,这叫做Element Diff;
    Diff算法

    在项目中使用react

1.运行npm i react react-dom

  • react:专门用于创建组件和虚拟DOM的,同时组件的生命周期都在这个包中
  • react-dom:专门进行DOM操作,最主要的应用场景,就是ReactDOM.render()

2.中index.html页面中,创建容器

1
<div id=“app”></div>

3.在index.js导入包:

1
2
import React from 'react';//创建组件、虚拟DOM元素,生命周期
import ReactDOM from 'react-dom';//把创建好的 组件和虚拟DOM放在页面上展示的。

4.创建虚拟DOM元素:

1
2
3
4
5
// 这是一个创建<h1 title="啊,五环" id="myh1">子节点</h1>
// 第一个参数 创建的标签名称
// 第二个参数 元素的属性
// 第三个参数 字节点
const myh1=React.createElement('h1',{title:'啊,五环',id:"myh1"},'子节点')

5.渲染:

1
2
3
4
ReactDOM.render(
myh1,//要渲染的虚拟DOM对象
document.getElementById('app')//指定容器
);

使用JSX语法

1.使用Babel转译器会把JSX转换成一个名为React.createElement()的方法调用。
配置Babel后可直接这样使用

1
2
3
4
5
const mytext="你好"
ReactDOM.render(
<h1>{mytext}</h1>,//要渲染的虚拟DOM对象
document.getElementById('app')//指定容器
);

2.jsx语法的本质:并不是直接渲染到页面上,而是内部通过Babel内部转换createElement形式,再渲染的
3.在jsx中混合写入js表达式:要把JS代码写到{}
4.在jsx中写注释推荐使用:{/*注释*/}
5.为jsx中的元素添加class类名:需要用className来替代classhtmlFor替换label的for属性

将组件单独抽离出为.jsx文件

新建Hello.jsx文件

1
2
3
export  default function Hello(){ //导出
return <div>这是Hello组件</div>
}

在index.js 中引入 即可使用

1
2
3
4
请问12312321312321321312321
123123
123
123
1
import Hello from "@/Hello"; //省略后缀名,是在webpack.config.js里面配置了,默认补全
  • 可以在webpack.config.js通过alias配置@代表src路径
1
2
3
alias: {
'@':path.join(__dirname,'../src'), //表示@为根目录中src的这一层路径
}

React的组件定义与使用

通过函数定义

1
2
3
4
5
6
7
function Hello(){
return <div>这是Hello组件</div>
}
ReactDOM.render(
<Hello/>,
document.getElementById('root')
);

为组件传递数据:

1
2
3
4
5
6
7
8
function Hello(props){
console.log(props)
return <div>这是Hello组件 ---{props.name}</div>
}
ReactDOM.render(
<Hello name='张三' />,
document.getElementById('root')
);

通过ES6类class来定义

1
2
3
4
5
6
7
8
9
10
11
12
13
class Hello extends React.Component {
render() {
return (
<div className="Hello">
这是Hello组件
</div>
);
}
}
ReactDOM.render(
<Hello/>,
document.getElementById('root')
);

通过class 创建的组件中,如果想使用外界传过来的props参数,不需要接收,直接通过this.props.xxx访问即可

三大核心属性1.state

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Square extends React.Component {
constructor(props) {
super(props);
this.state={
value:undefined,
}
}
btnClick(){
this.setState({value:'x'})
};
render() {
return (
<button onClick={ ()=>this.props.onClick()} className="square">
{this.props.value}
</button>
);
}
}

三大核心属性2.props

//props是只读的

三大核心属性3.refs与事件处理

1.refs的基础使用(字符串形式的ref不建议使用,建议使用回调函数的refs)

1
2
3
4
5
6
7
8
9
10
11
12
13
//ref 的使用,
export default class Refs extends React.Comp1onent {
ShowInputVal=()=>{
console.log(this.refs.myInput.value)
}

render(){
return (<div>
<input ref="myInput" />
<button onClick={this.ShowInputVal}>获取inpnt的值</button>
</div>)
}
}

2.回调形式的的refs

1
2
3
4
5
6
7
8
9
10
11
12
13
export default class Refs extends React.Component {
ShowInputVal = () => {
console.log(this.myInput.value)
}

render() {

return (<div>
<input ref={(node)=>{this.myInput=node}} />
<button onClick={this.ShowInputVal}>获取inpnt的值</button>
</div>)
}
}

3.createRef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export default class Refs extends React.Component {
//React.createRef() 调用后可以返回一个容器,该容器可以存储ref被标记的节点,该容器是'专人专用'
myRef=React.createRef()
ShowInputVal = () => {
console.log(this.myRef.current.value)
}

render() {

return (<div>
<input ref={this.myRef} />
<button onClick={this.ShowInputVal}>获取inpnt的值</button>
</div>)
}
}

事件处理
(1)通过onxxx属性指定事件处理函数
(2)通过event.targetdet得到发生事件等DOM元素对象
高阶函数

1
2
3
4
5
6
7
8
9

savaFormData=(val)=>{
//必须给一个函数给onChange作为回调
return (event)=>{
console.log(event.targetdet.value)
}
}
//必须给一个函数给onChange作为回调
<input onChange={this.savaFormData('username')} ref={this.myRef} />

两种创建组件的方式对比

注意:使用class创建的组件,有自己的私有数据(this.state)和生命周期函数;
使用function创建的组件,只有props,没有自己的私有数据和生命周期函数;

1.用构造函数创建出来的组件:叫做“无状态组件”
2.用class创建的组件:叫做”有状态组件”
3.什么情况下使用有状态组件?什么情况下使用无状态组件?

  • 如果一个组件需要有自己的私有数据,则推荐使用:class创建的有状态组件;
  • 如果一个组件不需要有私有数据,则推荐使用:无状态组件;
  • React官方说:无状态组件,由于没有自己的state和生命周期函数,所以运行效率高

有状态组件和无状态组件的本质区别就是:有无state属性和有无生命周期函数

生命周期

1.初始化阶段:由ReactDOM.render()触发–初次渲染

  1. constructor() //构造器
  2. componentWillMount() // 组件将要挂载
  3. render()
  4. componentDidMount() //组件完成挂载

2.更新阶段:由组件内部this.setSate()或父组件render触发

  1. shouldComponentUpdate() //控制组件更新的阀门钩子
  2. componentWillUpdate() //组件将要更新
  3. render()
  4. componentDidUpdate() //组件更新完毕

3.卸载组件

  1. componentWillUnmount() //卸载组件钩子