react 中的函数组件底层渲染原理
react
组件没有局部与全局之分,它是一个整体。这点跟vue
的组件化是不同的。- 要实现 react 中的全局组件,可以将组件挂在
react
上,这样只要引入了react
,就可以直接使用该组件。
函数式组件的创建
- 创建一个函数,函数中返回一个
jsx
或者jsx
元素,virtualdom
。 - 基于 es6 的模块导入导出方式,将函数作为模块的导出.可以忽略后缀名。
<Component />
<Component>...</Component>
- 命名:首字母大写,大驼峰命名。小写字母开头,编译器会认为这是一个标签,编译器也会报错。
关于 props 属性的细节知识
- 函数组件不能使用
this
关键字。 - 函数组件不能使用生命周期钩子。
- 子组件的
props
属性,不能直接修改。 - 获取子组件的
props
属性,需要使用props.xxx
。
对象的冻结
,密封
和不可扩展
- 被冻结的对象,不能添加、删除或修改其属性。也不能劫持对象。
Object.defineProperty
方法不能修改这些属性。Object.isFrozen
方法用来检测对象是否被冻结。 - 被密封的对象的属性,可以修改值,但是不能添加、删除。但不能劫持对象。
Object.isSealed
方法用来检测对象是否被密封。 - 不可扩展的对象,除了不能新增成员,其他操作都正常。
Object.isExtensible
方法用来检测对象是否可以扩展。
总结: 被冻结的对象,既是不可扩展的,也是密封的。被密封的,也是不可扩展的。
所以,我们在组件内部修改props
属性时,需要先拷贝一份,然后才能修改。否则会报错。
组件的默认值
- 函数组件.
defaultProps
属性,可以设置组件的默认值。
function Jsx({ name }) {
return (
<div>
Jsx
<hr />
<p>{name}</p>
</div>
);
}
Jsx.defaultProps = { name: "zs22222222" };
export default Jsx;
函数的类型校验
- 函数组件.
propTypes
属性,可以设置组件的默认值。 需要我们安装prop-types
库。
跟Component
组件一样,需要使用import
导入。
import PropTypes from "prop-types";
Child.defaultProps = { name: "zs22222222", age: 18 };
Child.propTypes = {
name: PropTypes.string,
age: PropTypes.oneOfType([
PropTypes.number.isRequired,
PropTypes.string,
PropTypes.bool,
]),
};
函数组件中的插槽处理
-
插槽的作用,就是将父组件中的内容,原封不动的传递给子组件。想办法让组件更加灵活,具有更强的复用性
-
数据值用属性
-
html 片段用插槽
-
children 属性,传递子组件的
jsx
元素,是数组的情况下,要使用下面的方式来接收,也可以使用React.Children
里面的方法来进行处理
-
插槽内容可以根据不同的需求,放到不同的位置。
-
静态组件和动态组件
function Vote() {
function handleSubmit() {}
function handleCancel() {}
return (
<div className="vote-box">
<div className="header">
<h2 className="title">标题</h2>
<span>15人</span>
</div>
<div className="main">
<p>支持人数: 10人</p>
<p>反对人数: 5人</p>
</div>
<div className="footer">
<button onClick={handleSubmit} className="btn btn-primary">
支持
</button>
<button onClick={handleCancel} className="btn btn-danger">
反对
</button>
</div>
</div>
);
}
export default Vote;
-
第一次渲染组件,执行函数,产生一个私有的上下文,把解析出来的
props
包括children
属性,保存到上下文,并冻结了props
属性,不可修改。返回一个jsx
元素的vdom
。渲染jsx
元素,生成virtualdom
。 -
当我们点击按钮,再次渲染组件时
修改上下文中的变量,私有作用于发生了变化,但是视图不会更新。所以称为静态组件。
除非在父组件中,修改了子组件的props
属性,才会重新渲染。 -
动态组件:实际项目中,我们会遇到在第一次渲染组件完成后,需要基于组件内部的状态变化,让组件可以更新,以呈现出不同的页面效果。 ====> 动态组件(
class
组件,hooks
组件) -
2、 初始化状态
状态:后期修改状态,可以触发视图的更新
需要手动初始化,如果我们没有去做相关的处理,则默认会往实例上挂载一个state
,初始值是null =>this,state=null
手动处理:
state = {
xxx:xxx
}
修改状态,控制视图更新this.state.xxx=xxx
:这种操作仅仅是修改了状态值,但是无法让视图更新想让视图更新,我们需要基于React.Component.prototype
提供的方法操作:「推荐」
- 1
this.setstate(partialstate)
既可以修改状态,也可以让视图更新 partialstate
:部分状态
this.setstate({
xxx:xxx
})
- 2
this.forceUpdate()
强制更新
forceUpdate
在类组件中生效的使用方法,当你必须使用这个api页面才更新的时候,说明你的业务代码中就已经出现了问题了。如果我们是基于 this.forceUpdate()
强制更新视图,会跳过 shouldcomponentUpdate
周期函数的校验,直接从willUpdate
开始进行更新,这时视图就一定会更新。
import { Component } from "react";
class Vote extends Component {
state = {
oppPerson: 0,
aggPerson: 0,
};
handleSubmit() {}
handleCancel = () => {
this.state.oppPerson++; //这种使用是不对的,
this.forceUpdate();
};
render() {
const { oppPerson, aggPerson } = this.state;
return (
<div className="vote-box">
<div className="header">
<h2 className="title">标题</h2>
<span>15人</span>
</div>
<div className="main">
<p>支持人数: {aggPerson}人</p>
<p>反对人数: {oppPerson}人</p>
</div>
<div className="footer">
<button onClick={this.handleSubmit} className="btn btn-primary">
支持
</button>
<button onClick={this.handleCancel} className="btn btn-danger">
反对
</button>
</div>
</div>
);
}
}
export default Vote;
父子组件的更新顺序
- vue中
- react中