【React学习笔记】第二章:React面向组件编程

ops/2025/1/18 17:40:17/

1.安装React 开发者工具调试

在这里插入图片描述
1.在Chrome应用商店中添加扩展程序:React Developer Tools
2.在github上下载压缩包:https://github.com/facebook/react-devtools/tree/v3

安装好之后运行react项目按F12打开浏览器控制台会多出两个tab栏:
在这里插入图片描述

● Components: 观察网页由多少个组件组成,每个组件有什么属性……
● Profiler: 用于记录网站性能,渲染时间,哪个组件加载的最慢……
本地调试使用 Liver Server 打开, alt b是打开本地磁盘的内容调试工具无法使用

2.React中组件的基本理解和使用

定义组件的两种方式:函数式组件和类式组件
-复杂组件:有状态(state)
-简单组件:无状态(state)

2.1 函数式组件

示例图:
在这里插入图片描述
代码

<body><!-- 准备好一个容器 --><div id="test"></div><!-- 引入react核心库,全局多了React对象 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入react-dom 用于支持react操作dom,全局多了ReactDOM对象  --><script type="text/javascript" src="../js/react-dom.development.js"></script><!-- 引入babel 用于将jsx转为js --><script type="text/javascript" src="../js/babel.min.js"></script><script type="text/babel">// 1.创建函数式组件function Demo() {return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>}// 2.渲染组件到页面ReactDOM.render(<Demo />, document.getElementById('test'))</script>
</body>

注意:
1.函数首字母必须大写,必须有返回值,必须要写组件标签,写好函数式组件后,由React调用。
2.函数中的this是 undefined,因为 babel 翻译后开启了严格模式(特点:禁止自定义函数的this指向window)
3.执行了ReactDom.render(<Demo / >, document.getElementById('test')),发生了什么?
-1.React解析组件标签,找到了 Demo组件。
-2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。

2.2 类式组件

示例图:
在这里插入图片描述
代码:

  <script type="text/babel">// 1.创建类式组件: 必须继承React.Component,必须有render且有返回值class MyComponents extends React.Component {// render是放在MyComponents的原型对象上,供实例使用。// render中的this是【MyComponent的实例对象】(MyComponent组件实例对象)。render () {console.log('render中的this', this)return <h2>我是通过类式定义的组件(适用于【复杂组件】的定义)</h2>}}// 2.渲染组件到页面ReactDOM.render(<MyComponents/>, document.getElementById('test'))</script>

注意:
1.必须继承React.Component,必须有render且必须有返回值
2.render是放在MyComponents的原型对象上,供实例使用;render中的this是【MyComponent的实例对
象】(MyComponent组件实例对象)。
3.执行了ReactDOM.render(<MyComponents/>, document.getElementById('test'))后,发生了什么?
  -1.React解析组件标签,找到了MyComponents组件
  -2.React发现组件是使用类定义的,随后new出来MyComponents的实例,并通过该实例调用原型上的
render方法
  -3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中

3.组件实例的三大核心属性—state

3.1 state的基本使用

状态(state)即数据,是组件内部的私有数据,只能在组件内部使用
state的值是对象,表示一个组件中可以有多个数据

初始化状态:

this.state = { count:0 }

获取state

<div>{this.state.count}</div>

修改state

this.setState({count:this.state.count + 1
})

3.2 案例:点击标题切换内容

描述:点击标题文字,切换内容"凉爽" <=>“炎热”
示例图:
在这里插入图片描述
代码

    class Weather extends React.Component {// 构造器调用了几次? —— 1次constructor(props){super(props);// 初始化状态this.state = {isHot: true,}// 解决changeWeather中的this指向问题: 把this改成Weather实例对象并生成一个新的函数this.toWeather = this.changeWeather.bind(this)}// render 调用了几次?——1+n次:初始化一次加状态更新的次数render() {// 读取状态const { isHot } = this.state;return <h1 onClick={this.toWeather}>今天天气很{isHot ? '炎热' : '凉爽'}</h1>}// changeWeather调用了几次? ——点几次调用几次changeWeather() {// changeWeather放在了Weather的原型对象上,供实例使用// 由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用的// 类中的方法默认开启局部的严格模式,所以changeWeather 中的this是undefined// console.log('点击了标题—changeWeather',this)// 获取原来的isHot值const isHot = this.state.isHot;// 状态不可直接更改,要借助一个内置的API-setState,不是替换是合并this.setState({ isHot: !isHot})}}ReactDOM.render(<Weather />, document.getElementById('test'))const title = document.getElementById('title');

总结:
1.构造器:this是该类的实例对象
 1)用于初始化状态,只会调用一次
 2)用于解决自定义函数中的this指向的问题
2.render:this是该类的实例对象
 1)用于读取state状态,根据状态的值做展示
 2)render中的 this 就是组件的实例对象
3.changeWeather:
 1)主要做两件事:获取state中isHot的值 ,更改状态
 2)状态不可直接更改,要借助一个内置的API—setState,且此操作是合并不是替换
4.为什么render中的this是类的实例对象?
ReactDOM.render(<Weather />, document.getElementById('test'));
 react中 new Weather() 拿到了这个实例(w1),然后通过w1.render进行调用
5.为什么 changeWeather 中的this是undefined?
 这是自定义的点击事件,是作为onClick的回调,所以不是通过实例调用的。由于类中的方法默认开启局部的
 严格模式,所以changeWeather 中的this是undefined(解决方式是在构造器中使用bind)

3.3 State的简写方式

    class Weather extends React.Component {constructor(props){super(props);// this.changeWeather = this.changeWeather.bind(this)}// 初始化状态state = {isHot1: true,}render() {const { isHot } = this.state;return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}</h1>}// 自定义方法:赋值语句 + 箭头函数,这样this就是组件实例对象changeWeather = () => {console.log(this)const isHot = this.state.isHot;this.setState({ isHot: !isHot})}
}

3.4 总结

1.组件自定义的方法中 this 为 undefined,如何解决?
 -a. 强制绑定this:通过函数对象的bind()
 -b.箭头函数
2.状态数据不能直接修改或更新
3.组件中render方法中的 this 为组件实例对象

4.组件实例的三大核心属性—props

4.1 props的基本使用

组件标签的所有属性都保存在 props 中
作用:
 1.通过标签属性从组件外向组件内传递变化的数据
 2.props 只读,组件内部不能修改 props 数据
使用:
 1.读取某个属性值 this.props.name
 2.扩展属性:将对象的所有属性通过 props 传递
<Person {...person}/>
 3.对props中的属性值进行类型限制和必要性限制
  ● 方式1:(React v15.5 开始已弃用)
  Person.propTypes = { name: React.PropTypes.string.isRequired }
  ● 方式2:(新,需引入 prop-types.js)
  Person.propTypes = { name: PropTypes.string.isRequired }
 4.设置默认属性值
Person.defaultProps = { age: 18, sex: '男' }
 5.组件类的构造函数 - constructor
 super()是否接收并传递props取决于是否希望在构造器中通过 this 访问 props,类中的构造器能省略就省略
  ● super(props):接收props并传递,可以通过实例访问 props
  ● super(): 无法通过实例访问props, 构造器中this.props 为undefined

    // 创建组件class Person extends React.Component {render () {const { name, age, sex } = this.props;return (<ul><li>姓名:{ name }</li><li>性别:{ sex }</li><li>年龄:{ age }</li></ul>)}}
// 传递 props 方式1:
ReactDOM.render(<Person name="tom" age="18" sex="" />, document.getElementById('test'))
ReactDOM.render(<Person name="jerry" age="20" sex="" />, document.getElementById('test2'))// 传递 props 方式2:批量传递
const p = { name: 'tom', age: 18, sex: '女' }
ReactDOM.render(<Person {...p} />, document.getElementById('test'))

4.2 对props进行限制

4.2.1 对标签属性进行类型、必要性的限制以及默认值的设置

对标签属性进行类型、必要性的限制

   Person.propTypes = {name: PropTypes.string.isRequired,sex: PropTypes.string,age: PropTypes.number,speak: PropTypes.func}

指定默认的标签属性值

   Person.defaultProps = {sex: '不男不女',age: 18}
4.2.2 示例
    // 创建组件class Person extends React.Component {render () {const { name, age, sex } = this.props;return (<ul><li>姓名:{ name }</li><li>性别:{ sex }</li><li>年龄:{ age }</li></ul>)}}// 对标签属性进行类型、必要性的限制Person.propTypes = {name: PropTypes.string.isRequired,sex: PropTypes.string,age: PropTypes.number,speak: PropTypes.func}//  指定默认的标签属性值Person.defaultProps = {sex: '不男不女',age: 18}ReactDOM.render(<Person name="jerry" age={20} sex="" speak = {speak} />, document.getElementById('test2'))ReactDOM.render(<Person name="老刘" />, document.getElementById('test3'))function speak(){console.log('我说话了')}

4.3 props的简写方式

把对标签属性的限制及默认值的设置写在类中
不加 static 是加给类的实例,加上static是加在类本身

    class Person extends React.Component {// 对标签属性进行类型、必要性的限制static propTypes = {name: PropTypes.string.isRequired,sex: PropTypes.string,age: PropTypes.number,speak: PropTypes.func}//  指定默认的标签属性值static defaultProps = {sex: '男',age: 18}render () {const { name, age, sex } = this.props;return (<ul><li>姓名:{ name }</li><li>性别:{ sex }</li><li>年龄:{ age }</li></ul>)}}ReactDOM.render(<Person name="Jerry" />, document.getElementById('test'))

4.4 函数式组件使用props

通过函数可以接收参数的特性

    // 对标签属性进行类型、必要性的限制Person.propTypes = {name: PropTypes.string.isRequired,sex: PropTypes.string,age: PropTypes.number,speak: PropTypes.func}//  指定默认的标签属性值Person.defaultProps = {sex: '男',age: 18}// 定义函数式组件function Person (props) {const { name, age, sex } = props;return (<ul><li>姓名:{ name }</li><li>性别:{ sex }</li><li>年龄:{ age }</li></ul>)}ReactDOM.render(<Person name="Jerry" />, document.getElementById('test'))

5.组件实例的三大核心属性—refs与事件处理

5.1使用ref的三种方式

  • 字符串形式
    • 定义:<input ref="input1" />
    • 使用:const { value } = this.refs.input1;
  • 回调函数形式
    • 定义:<input ref={(c) => this.input1 = c} />
    • 使用:const { value } = this.input1
  • createRef
    • 定义:<input ref={this.myRef} />
    • 使用:const { value } = this.myRef.current
5.1.1 字符串形式的ref

在条件允许的情况下,尽可能避免使用字符串形式的ref

class Demo extends React.Component{render() {return (<div><input ref="input1" type="text" placeholder="点击按钮提示数据" /><button onClick={this.showData}>点击提示左侧数据</button>              </div>)}showData = () => {const { value } = this.refs.input1;alert(value)}
}
ReactDOM.render(<Demo />, document.getElementById('test'));
5.1.2 回调函数形式的ref
class Demo extends React.Component{render() {return (<div><input ref={(c) => this.input1 = c } type="text" placeholder="点击按钮提示数据" /><button onClick={this.showData}>点击提示左侧数据</button>              </div>)}showData = () => {const { value } = this.input1;alert(value)}
}
ReactDOM.render(<Demo />, document.getElementById('test'));

扩展: ref={(c) => this.input1 = c内联形式的ref在创建时执行一次,更新页面时会执行两次。可以使用class 的绑定函数的方式来避免这个问题。但内联形式还是常用的。

class Demo extends React.Component{// 通过将ref的回调定义成 class 的绑定函数的方式可以避免每次渲染时会被执行两次的问题saveInput = (c) => {this.input1 = c;}render() {return (<div><input ref={this.saveInput} type="text" placeholder="点击按钮提示数据" /><button onClick={this.showData}>点击提示左侧数据</button>              </div>)}showData = () => {const { value } = this.input1;alert(value)}
}
ReactDOM.render(<Demo />, document.getElementById('test'));
5.1.3 createRef的形式

1.React.createRef()调用后可以返回一个容器,该容器可以存储ref所标识的节点;
2.this.myRef是使用createRef创建的一个容器,把当前ref所在的节点(input)直接存储到这个容器里
3.需要几个ref就需要创建几个

class Demo extends React.Component{myRef = React.createRef();showData = () => {const { value } = this.myRef.current;alert(value)}render() {return (<div><input ref={this.myRef} type="text" placeholder="点击按钮提示数据" /><button onClick={this.showData}>点击提示左侧数据</button>              </div>)}
}
ReactDOM.render(<Demo />, document.getElementById('test'));

5.2 事件处理

5.2.1事件绑定

1.通过 onXxx属性指定事件处理函数(注意大小写)
 a. react事件绑定语法与DOM事件语法相似
  - 语法:on + 事件名称 = { 事件处理程序} , 如: onClick = { () =>{} }
  - React事件采用驼峰命名法,如:onMouseEnter、onFocus
 a. React使用的是自定义(合成)事件,而不是使用的原生DOM事件——为了更好的兼容性
 b. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)——为了高效
2.通过event.target得到发生事件的DOM元素对象 ——不要过度使用ref

示例:

// 类式组件
class Header extends Component {// 按钮点击事件handleClick = (e) => {}render() {return (<div className="todo-header"><button onClick={this.handleClick}></button></div>)}
}
5.2.2 事件对象

可以通过事件处理程序的参数获取到事件对象

function handleClick(e){e.preventDefault()console.log('事件对象:',e)
}
// 绑定事件
<a onClick={handleClick}></a>

6.组件生命周期

6.1 生命周期图(旧)

在这里插入图片描述
生命周期的三个阶段(旧)

  1. 初始化阶段执行的生命周期(4个)ReactDOM.render() 触发
    1.constructor()
    2.componentWillMount() — 组件将要挂载时的钩子
    3.render() — 组件挂载的钩子
    4.componentDidMount() — 组件挂载完毕的钩子
  2. 更新阶段执行的生命周期(4个) 由组件内部this.setState() 或父组件重新渲染 render 触发
    1.shouldComponentUpdate — 控制组件是否更新的钩子,若返回 false,则下面的都不执行
    2.componentWillUpdate — 组件将要更新的钩子
    3.render()
    4.componentDidUpdate() — 组件更新完毕的钩子
  3. 卸载组件执行的生命周期(1个)ReactDOM.unmountComponentAtNode() 触发
    1.componentWillUnmount() — 组件将要卸载

作为子组件时,会先执行这个生命周期

  • componentWillReceiveProps() — 组件将要接收新的props的钩子,第一次不执

shouldComponentUpdate返回false执行的生命周期(1个)

  • shouldComponentUpdate()

forceUpdate() 强制更新执行的生命周期(3个)

  • componentWillUpdate()
  • render()
  • componentDidUpdate()

常用的生命周期

  1. componentDidMount()
    做一些初始化的事:开启定时器、发送网络消息、订阅消息
  2. componentWillUnmount()
    做一些收尾的事:关闭定时器、取消订阅消息

6.2 生命周期(新)

react 版本17.0.1

在这里插入图片描述

生命周期的三个阶段(旧)

  1. 初始化阶段执行的生命周期(4个)ReactDOM.render() 触发
    1.constructor()
    2.getDerivedStateFromProps()
    3.render()
    4.componentDidMount()
  2. 更新阶段执行的生命周期(4个) 由组件内部this.setState() 或父组件重新渲染 render 触发
    1.getDerivedStateFromProps
    2.shouldComponentUpdate
    3.render()
    4.getSnapshotBeforeUpdate()
    5.componentDidUpdate()
  3. 卸载组件执行的生命周期(1个)ReactDOM.unmountComponentAtNode() 触发
    1.componentWillUnmount()
static getDerivedStateFromProps (props, state) {console.log('getDerivedStateFromProps')return null;
}getSnapshotBeforeUpdate () {console.log('getSnapshotBeforeUpdate');return null;
}componentDidUpdate (preProps, preState, snapshotValue) {console.log('componentDidUpdate', preProps, preState, snapshotValue)
}

6.3 总结

重要的生命周期:

  1. render: 初始化渲染或重新渲染调用
  2. componentDidMount: 开启监听,发送ajax请求
  3. componentWillUnmount: 清理定时器……

即将废弃三个生命周期钩子,下一个大版本需要加前缀才能使用

  1. UNSAFE_componentWillMount()
  2. UNSAFE_componentWillReceiveProps()
  3. UNSAFE_componentWillUpdate()

新旧对比(17.0.1):

  • 废弃了三个生命周期钩子:
  1. componentWillMount()
  2. componentWillReceiveProps()
  3. componentWillUpdate()
  • 新增了两个生命周期钩子:
  1. getDerivedStateFromProps()
    a. 要定义为静态方法,两个参数:props, state
    b.要有返回值:null 或者 状态对象
    c.场景:state的值在任何时候都取决于 props
  2. getSnapshotBeforeUpdate()
    a.任何返回值将作为参数传递给componentDidUpdate()
    b.场景:组件在发送更改之前从DOM捕获一些信息(滚动位置)

7.关于表单处理

7.1 受控组件

其值受到React控制的表单元素

  • html中表单元素时可输入的,也就是有自己的可变状态
  • 而React中可变状态通常保存在state中,并且只能通过setState()方法来修改
  • React将state与表单元素值value绑定到一起,由state的值来控制表单元素的值

步骤:
1.在state中添加一个状态,作为表单元素的value值(控制表单元素值的来源)
2.给表单元素绑定change事件,将表单元素的值设置为state的值(控制表单元素值的变化)

<input type="text" value = { this.state.txt } onchange={this.handleContent}>

http://www.ppmy.cn/ops/151145.html

相关文章

Tesla Free - Fall attack:特斯拉汽车网络安全攻击事件分析

文章目录 一、Tesla Free - Fall attack&#xff1a;特斯拉汽车网络安全事件纪要1. 引言2. 攻击流程2.1 攻击切入点2.2 系统入侵2.3 CAN 总线操控 3. 影响后果4. 特斯拉应对措施5. 研究意义二、安全攻击事件技术分析以及相应的检测和缓解措施 一、Tesla Free - Fall attack&…

如何在后端使用redis进行缓存,任意一种语言都可以

在后端使用 Redis 可以显著提升应用的性能&#xff0c;特别是在处理高并发请求、缓存数据、会话管理、消息队列等场景。以下是关于如何在 Spring Boot 项目中集成和使用 Redis 的详细讲解。 1. 添加依赖 首先&#xff0c;在 pom.xml 文件中添加 Redis 相关的依赖。Spring Boo…

Springboot + vue 图书管理系统

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;欢迎留言讨论 &#x1f525;&#x1f525;&…

如何通过 Nginx 实现 CouchDB 集群的负载均衡并监控请求分发

在现代分布式系统中&#xff0c;负载均衡是确保高可用性和性能的关键组件。CouchDB 是一个强大的分布式数据库&#xff0c;而 Nginx 是一个高性能的反向代理和负载均衡器。本文将详细介绍如何通过 Nginx 实现 CouchDB 集群的负载均衡&#xff0c;并监控请求被分发到哪一台 Couc…

linux系统监视(centos 7)

一.系统监视 1.安装iostat&#xff0c;sar&#xff0c;sysstat&#xff08;默认没有&#xff0c;安装过可以跳跃&#xff09; iostat 和 sar&#xff1a; 同样&#xff0c;iostat 和 sar 是 sysstat 软件包的一部分。使用以下命令安装&#xff1a;sudo yum install sysstat解释…

图解Git——分布式Git《Pro Git》

分布式工作流程 Centralized Workflow&#xff08;集中式工作流&#xff09; 所有开发者都与同一个中央仓库同步代码&#xff0c;每个人通过拉取、提交来合作。如果两个开发者同时修改了相同的文件&#xff0c;后一个开发者必须在推送之前合并其他人的更改。 Integration-Mana…

【Linux】gdb_进程概念

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

基于微信小程序的电子点菜系统设计与实现(KLW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…