# 函数式组件的细节知识 (类Vue中具名插槽的原理)
# 创建函数式组件
函数式组件: 函数里面返回一个JSX元素
函数式组件
1、调取组件可以是单闭合,也可以是双闭合 (双闭合调用,可以把子元素当做属性中的children传递给组件,类似于Vue中的slot)
2、React. Children提供对应的方法专门用来处理传递进来的子元素的children的
3、底层运作的时候,如果虚拟DOM对象的type是一个函数(或者一个类),首先会把函数执行(把解析出来的props传递给这个函数),函数会把一个新的虚拟DOM对象返回,最后整体渲染
4、传递进来的属性是只读的(只能获取,不能直接修改其里面的值),如果非要修改某一个值,可以把其赋值给一个变量(state: 状态)再去修改变量(状态); 再或者把属性深克隆一分,供调取和修改;
# Clock时钟组件
function Clock(props) {
let index = props. index
index = 1000
// props. index = 100 // 是错误的!! 只读属性
return <div className={props. className} style={props. style}>
{new Date().toLocaleString()}
{index}
</div>
}
// ReactDom. render 将虚拟DOM对象转换为真实DOM对象
ReactDom. render(<>
<Clock index={1} className="text" style={{ color: 'red' }}>
// props.children
<span>前端小屋</span>
</Clock>
</>, document. getElementById('root'))
// React. createElement 创建虚拟DOM对象
// console. log(React. createElement(Clock, null))
函数式组件的静态性
函数式组件属于静态组件,调取组件渲染出一个结果,后续除非重新渲染组件,否则第一次渲染的内容不会改变(当然React Hooks可以帮我们解决这个问题)
要想实时渲染 需要让虚拟DOM每次都有更新,才会触发由虚拟DOM转变成真实DOM,导致页面渲染
# 函数式组件的静态性
function Clock(props) {
let time = new Date(). toLocaleString()
setInterval(_ => {
time = new Date().toLocaleString()
console.log(time) // 该time会变
}, 1000)
return <div>
{time} // 该值不变,则一直为初始渲染的结果
</div>
}
ReactDom. render(<>
<Clock></Clock>
</>, document. getElementById('root'))
# 创建类组件
类组件
创建一个类继承React. Component/React. PureComponent
1、渲染的时候的发现type是一个类,则会创建当前类的实例
2、同样会把解析出来的props传递给当前这个类,并且REACT会帮我们把props挂载到当前类的实例上(this. props即可操作属性),但是默认情况下是执行完constructor才把props挂载到实例上的,所以在constructor中无法基于this. props获取
3、super()类似于call继承 React. Component. call(this, props),React. component()执行时,会把解析出来的props继承到当前类的实例上,前提是super(props)
4、定义在constructor函数之外且当前类类里面的方法或状态都是挂载在原型上的,直接基于this. xxx调用即可
前面加static,如:static defaultProps = {... } 是给当前类设置属性
若 使用ES7写法,省略constructor,直接写state = {... },则是给实例设置属性,直接基于this. xxx调用即可
# 类组件的属性传递
class Clock extends React. Component {
constructor(props) {
// super(props) == this.props
super(props); // 类似于call继承 React.Component.call(this,props)
}
render() {
let time = new Date().toLocaleString()
return <div>
{time}
</div>
}
// ...
}
ReactDom. render(<>
<Clock index={1}>
<span>前端小屋</span>
</Clock>
</>, document. getElementById('root'))
# 类组件中的数据驱动
受控组件:顾名思义,受状态管控的组件,即基于数据驱动视图的渲染(类组件也是动态组件) 数据即组件状态 受控组件:直接操作DOM的 ref
setState
setState(partialState, callback)
partialState: 部分状态
callback: 当状态更新,视图重新渲染完触发的回调函数 (类似于vue中的$nextTick)
class Clock extends React. Component {
constructor(props) {
super(props);
// 初始化状态写法1 目的:(把后续需要用到的状态初始化)
this.state = {
time: new Date().toLocaleString()
}
}
// 初始化状态写法2 ES7中规定下述写法是直接给实例设置属性
state = {
time: new Date().toLocaleString()
}
render() {
// 在渲染的时候使用状态
let time = new Date().toLocaleString()
return <div>
{this.state.time}
</div>
},
// 第一次加载完成的生命周期函数
componentDidMount() {
setInterval(_ => {
// 可以修改状态,但是不能控制视图重新渲染
// this.state.time = new Date().toLocaleString()
this.setState({
time: new Date().toLocaleString()
})
}, 1000)
}
}
ReactDom. render(<>
<Clock index={1}>
<span>前端小屋</span>
</Clock>
</>, document. getElementById('root'))
# 类组件方法绑定的几种形式
组件绑定事件,并传递参数,在组件内绑定箭头函数,保证方法中的this指向当前类的实例
class Clock extends React. Component {
render() {
...
return <div>
...
<button onClick={this.handle}></button>
<button onClick={ev => {
this.handle(ev, 100)
}}></button>
<button onClick={this.handle.bind(this, 100)}></button>
</div>
},
handle = (ev, n) => {
console.log(ev, n)
}
}
# 类组件中ref获取当前元素
ref在真实项目中的写法
ref拓展
<button ref={
函数表达式写法 <br>
x => 当前操作的元素 <br>
this.btn = x; 直接把元素挂载到实例,不走refs <br>
}>
class Clock extends React. Component {
render() {
...
return <div>
...
// <button ref="btn">获取元素</button>
<button ref={
// 函数表达式写法
// x => 当前操作的元素
this.btn = x; // 直接把元素挂载到实例
}></button>
</div>
},
handle = (ev, n) => {
console.log(ev, n)
},
componentDidMount() {
this.autoTimer = setInterval(_ => {
this.setState({
time: new Date().toLocaleString()
})
}, 1000)
// 获取DOM元素
this.btn.addEventListenter('click', _ => {
clearInterval(this.autoTimer)
})
}
}
# 类组件中属性的设置规则
类组件中,若想给组件设置属性规则,需使用prop-types插件
属性规则设置: prop-types
1、安装插件
2、设置默认值 Vote. defaultProps = {}
3、设置传递的值类型和是否必传项等 Vote. propTypes = {}
4、render函数里将属性解构出来
class Vote extends React. Component {
// 设置默认属性 (不传的情况下)
static defaultProps = {
supNum: 0
oppNum: 0
};
// 设置传递的值类型 和 是否必传
static proTypes = {
title: PropType.string.isRequired,
supNum: PropType.number,
oppNum: PropType.number
}
render() {
let { title, supNum, oppNum } = this.props
}
}
# React中的事件绑定
React中的事件绑定是合成事件绑定(获取的事件对象也是合成事件对象)
合成事件是基于事件委托实现的(把所有的事件绑定给最外层的元素, 不论点击到哪一个都会冒泡到最外层)
目的是:实现PC和移动端的兼容性,例如:移动端的click存在300ms延迟,我们设置的onClick在PC端被识别为click,在移动端被识别为touch事件模型
事件对象也是React内部合成的一套对象,但是对于我们获取和操作没有影响,因为它把每一个属性值都get/set了
ev. persist()变为原生事件对象
🎉 💯