文章目录
- 组件
-
- 函数式组件
- class 组件
- class组件与函数式组件的区别
- 组件实例的三大属性
-
- 三大属性之state
-
- setState 是异步更新的
- setState 什么时候是异步的
- 三大属性之props
-
- props.children 实现类似 Vue 插槽的功能
- 对props中的属性的值进行类型限制和必要性限制
- 三大属性之refs
-
- createRef创建 ref 容器
- 回调形式获取DOM节点
组件 React组件根据定义形式的不同,可以分为
函数组件
与 class 组件
。在满足需求的情况下,能使用函数式组件就不要使用class组件
注意:组件名称必须以大写字母开头。React 会将以小写字母开头的组件视为原生 DOM 标签。函数式组件
函数式组件在使用时,会直接调用该函数,并传入props
,没有自己的实例,执行完即销毁,无法存储state
,只能接收props
而没有state
和refs
function MyComponent(props) {
return (
{/*组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props*/}
我是函数式组件---{this.props.name}
)
}
该函数是一个有效的 React 组件,因为它接收唯一带有数据的 “props”(代表属性)对象,并返回一个 React 元素。这类组件被称为“函数组件”,因为它本质上就是 JavaScript 函数。
class 组件
class组件有自己的状态(state
)、refs
和props
。react每次使用class组件时,都会实例化这个组件,然后重新执行组件实例的render方法(即用多少次,就实例化多少个组件),同时每次有状态(state
)更新,就会重新执行render
方法
import React from 'react';
export default class LoginComponent extends React.Component {
state = {isLogin: true}
// 必须实现 render 方法,并返回一个 react 元素
render(){
return (
)
}
// 通过赋值语句将箭头函数赋值给组件自身的属性,以解决事件回调中 this 指向的问题
handleClick = () => {
// 1、要更改状态不能直接通过this.state.xxx = xxx来访问,而是使用下面的 setState 方法
// 2、当有 state 更新时,react会重新执行组件实例的 render 方法来重新渲染更改
this.setState({
isLogin: !this.state.isLogin
})
}
}
class组件与函数式组件的区别
class组件 | 函数式组件 | |
---|---|---|
生命周期 | 有 | 无 |
组件实例 | 有 | 无 |
state和setState | 有 | 无 |
- 大型组件很难拆分和重构,变得难以测试
- 相同业务逻辑分散到各个方法中,可能会变得混乱
- 复用逻辑可能变得复杂,如 HOC 、Render Props
hook 使用----https://blog.csdn.net/weixin_43842373/article/details/120994912?spm=1001.2014.3001.5502组件实例的三大属性 组件实例的三个核心属性分别为:
state
、props
、refs
三大属性之state
state
是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)- class组件被称为"状态机",通过更新组件的
state
会重新触发组件的render
方法来重新渲染页面,state
的状态数据不能直接修改或更新,需要借助setState
来更新或修改,且更新是一种合并,不是替换。
state
,react重新触发组件实例的render
方法重新渲染,完成登陆切换import React from 'react';
export default class LoginComponent extends React.Component {
state = {isLogin: true}
// 必须实现 render 方法,并返回一个 react 元素
render(){
return (
)
}
// 通过赋值语句将箭头函数赋值给组件自身的属性,以解决事件回调中 this 指向的问题
handleClick = () => {
// 1、要更改状态不能直接通过this.state.xxx = xxx来访问,而是使用下面的 setState 方法
// 2、当有 state 更新时,react会重新执行组件实例的 render 方法来重新渲染更改
this.setState({
isLogin: !this.state.isLogin
})
}
}
setState 是异步更新的
先来看看
setState
是什么,看下图:文章图片
setState()
会对一个组件的 state 对象安排一次异步
更新。当 state 改变了,该组件就会重新渲染。注意:
调用setState
其实是异步更新的 —— 不要指望在调用 setState 之后,this.state 会立即映射为新的值。如果你需要基于当前的 state 来计算出新的值,那你应该传递一个函数,而不是一个对象(对象写法其实是函数写法的语法糖),就可以确保每次的调用都是使用最新的state
incrementCount() {
// 注意:这样 *不会* 像预期的那样工作。
this.setState({count: this.state.count + 1});
}handleSomething() {
// 假设 `this.state.count` 从 0 开始。
this.incrementCount();
this.incrementCount();
this.incrementCount();
// 当 React 重新渲染该组件时,`this.state.count` 会变为 1,而不是你期望的 3。// 这是因为上面的 `incrementCount()` 函数是从 `this.state.count` 中读取数据的,
// 但是 React 不会更新 `this.state.count`,直到该组件被重新渲染。
// 所以最终 `incrementCount()` 每次读取 `this.state.count` 的值都是 0,并将它设为 1。// 问题的修复参见下面的说明。
}
如何解决
setState
异步更新带来的问题?可以给setState
传递一个可以返回对象的函数,而不是一个对象。如下代码:incrementCount() {
// 给 setState 传递一个函数,而不是一个对象
this.setState((preState) => {
// 返回的对象会与 preState 合并为新的 state
return {count: preState.count + 1}
});
}handleSomething() {
// 假设 `this.state.count` 从 0 开始。
this.incrementCount();
this.incrementCount();
this.incrementCount();
// 如果你现在在这里读取 `this.state.count`,它还是会为 0。
// 但是,当 React 重新渲染该组件时,它会变为 3。
}
setState 什么时候是异步的
目前,在事件处理函数内部的例如,如果setState
是异步的。
Parent
组件 和 Child
组件 在同一个 click 事件中都调用了 setState
,如果setState
不进行异步更新,那么而就会出现这样的问题:(Child
组件被渲染两次,从而影响性能)- 当
Child
组件内部的setState
完成之后,Child
组件会被重新渲染。(Child
第一次渲染) - 当
Parent
组件内部的setState
完成之后,Parent
组件会连带着Child
组件一起被重新渲染。(Child
第二次渲染)
setState
使用异步更新,那么在开始重新渲染之前,React 会有意地进行“等待”,直到所有在组件的事件处理函数内调用的 setState()
完成之后。这样就可以确保 Child
不会被重新渲染两次。取而代之的是,React 会将该 state
“冲洗” 到浏览器事件结束的时候,再统一地进行更新。这种机制可以在大型应用中得到很好的性能提升。三大属性之props
props
的作用:通过标签属性从组件外向组件内传递变化的数据给props
组件内部不建议修改props的数据,数据的更新借助于state
- 每个组件对象中对会含有
props
属性 - 组件标签的所有属性都保存在
props
中,即相当于自定义属性 - 组件无论是使用函数声明还是通过
class
声明,都决不能修改自身的props
1、创建一个函数式组件和一个class组件
function MyComponent(props) {
return (
{/*组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props*/}
我是函数式组件---{this.props.name}
)
}class ClassComponent extends React.Component {
props = { name: '' } // 自定义属性 name
render (
我是Class组件---{this.props.name}
)
}
在使用时如下:
props.children 实现类似 Vue 插槽的功能
参考官网—https://zh-hans.reactjs.org/docs/react-api.html#reactchildrenreact是单向数据流,
map、forEach、only、count、toArray
props
是我们从上个组件传值传下来的集合,每一个props
都应该对应的是从上个组件传过来的值。但是这里有一个例外,那就是this.props.children
。如下示例:import React from 'react'
import ReactDom from 'react-dom'
class PropsChildren extends React.Component {
constructor(props) {
super(props)
}
render() {
console.log(this.props.children) // 接收标签体内容
return (
{this.props.children}
)
}
}ReactDOM.render(
// 通过闭合标签写入标签体内容,写入的标签体内容会自动传给 props.children标签体内容---props.children
这是一个时钟组件
document.getElementById('root')
);
效果如下:
文章图片
可以看到:
this.props.children
的值有三种可能:- 如果当前组件没有子节点,它就是
undefined
; - 如果有一个子节点,数据类型是
Object
或者String
,这取决于写入的标签体内容是一个组件还是普通字符串; - 如果有多个子节点,数据类型就是
Array
。
this.props.children.map
遍历它的时候可能会抛出错误。React 提供一个工具方法 React.Children
来处理 this.props.children 。可以用 React.Children.map
来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined
还是 Object Array
。示例如下class MyList extends React.Component {
render() {
return ({
React.Children.map(this.props.children, function(child){
console.log(child)// MyList里面有节点,对这三个节点进行循环
return - child
;
})
}
);
}
}
ReactDOM.render(
>飞剑侠
>武尊神
>逆天魔
,document.getElementById('example'));
对props中的属性的值进行类型限制和必要性限制
在使用
props
传递变化的数据时,有时组件内部对于数据有一定的要求,就需要对props
的属性值进行类型限制和必要性限制常用方法是使用
prop-types
库进行限制(需引入prop-types
库):import PropTypes from 'prop-types';
import React from 'react'
export default class ClassComponent extends React.Component {
props = { // 自定义属性 name, age, speak
name: '',
age: 0,
speak: null
}
// 对props进行限制
static propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
age:PropTypes.number,//限制age为数值
speak:PropTypes.func,//限制speak为函数
} render (
我是Class组件---{this.props.name}
)
}
三大属性之refs
refs
可以获取DOM节点,以此来操作DOM。在组件内使用,组件内的便签可以定义ref
属性来表示自己注意:字符串形式的 ref 使用方式已不被 React 官方推荐,尽量减少使用createRef创建 ref 容器
class Demo extends React.Component{
/* React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的 */
myRef = React.createRef() // 1、创建ref容器
myRef2 = React.createRef()
//展示左侧输入框的数据
showData = https://www.it610.com/article/()=>{ alert(this.myRef.current.value);
}
//展示右侧输入框的数据
showData2 = ()=>{ alert(this.myRef2.current.value);
}
render(){
return(
{/*2、在标签上使用 ref 之后,myRef 容器中便存放了这个节点*/}
)
}
}
回调形式获取DOM节点
class Demo extends React.Component{
//展示左侧输入框的数据
showData = https://www.it610.com/article/()=>{
const {input1} = this // 2、从 this.input1 中获取DOM节点
alert(input1.value)
}
//展示右侧输入框的数据
showData2 = ()=>{
const {input2} = this
alert(input2.value)
}
render(){
return(
{/*1、通过回调函数将 DOM 节点赋值给 input1 属性*/}
this.input1 = c } type="text" placeholder="点击按钮提示数据"/>
this.input2 = c } type="text" placeholder="失去焦点提示数据"/>
)
}
}
推荐阅读
- React|React组件三大核心属性(二)——props
- react技术栈及全家桶|react-router-dom v6 版本使用内容详解
- #|React组件实例的三大属性
- react.js|react-router-dom V6的配置使用
- react|react 路由(react-router-dom 的使用)
- JS知识总结|【JavaScript复习十八】预解析
- java|含文档+PPT+源码等]精品微信小程序校园第二课堂+后台管理系统|前后分离VUE[包运行成功]计算机毕业设计项目源码Java毕设项目
- 毕业设计|基于Nodejs的心理咨询微信小程序的设计和实现
- JS知识总结|【JavaScript复习十七】作用域以及变量提升