02_React面向组件编程--基本使用与理解、组件实例的三大核心属性与事件处理

embedded/2024/9/20 4:01:52/ 标签: react.js, javascript, 前端

基本使用与理解、组件实例的三大核心属性与事件处理

    • 一、基本理解与使用
      • 1、函数式组件
      • 2、类的复习
      • 3、类式组件
      • 4、简单组件和复杂组件
    • 二、组件实例的三大核心属性 1:state
      • 1、例子,点击文字切换 凉爽和炎热
        • 1.1 复习--原生事件绑定方式
        • 1.2 复习--类中的方法 this 指向
        • 1.3 类的复习---类中添加属性
        • 1.3 例子的简写。state 的简写
      • 2、理解
      • 3、强烈注意
    • 三、组件实例的三大核心属性 2:props
      • 1、例子:自定义用来显示一个人员信息的组件
        • 1.1 要求:
        • 1.2 复习--展开运算符(...)
        • 1.3 对传递的属性(props)进行校验
        • 1.4 复习-- 类的关键字 static
        • 1.5 props 简写方式
        • 1.6 函数式组件使用 props。三大属性中函数式组件仅能使用 props
      • 2、理解
      • 2、理解
      • 3、作用
      • 4、编码操作
    • 四、组件实例的三大核心属性 3:refs 与事件处理
      • 1、例子
        • 1.1 需求:自定义组件,功能说明如下:
        • 1.2 过时 API :String 类型的 Refs
        • 1.3 回调函数形式的 ref
        • 1.4 createRef (官方推荐写法)
      • 2、理解
      • 3、编码
      • 4、事件处理

注意:当前 react 版本为 16.8.0

一、基本理解与使用

1、函数式组件

/**
_ 执行了 ReactDOM.render(, … 之后,发生了什么?
_ 1.React 解析组件标签,找到了 MyComponent 组件
_ 2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟 DOM 转为真实 DOM,随后呈现在页面中
_/

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>函数式组件</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">//   1、创建函数式组件function MyComponent() {console.log(this) // babel 开启严格模式,将自定义的 this 不再是window,而是undefinedreturn <h2>我是用函数定义的组件(适用于【简单组件】)的定义</h2>}// 2、渲染组件到页面ReactDOM.render(<MyComponent />, document.getElementById('test'))/*** 执行了 ReactDOM.render(<MyComponent/>, .... 之后,发生了什么?* 1.React 解析组件标签,找到了 MyComponent 组件* 2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟 DOM 转为真实 DOM,随后呈现在页面中*/</script></body>
</html>

2、类的复习

总结:
1、类中的构造器不是必须要写的,要对实例进行一些初始化的操作,如添加指定属性时才写
2、如果 A 类继承了 B 类且 A 类中写了构造器,那么 A 类构造器中 super 时必须要调用的
3、类中所定义的方法,都是放在了类的原型对象上,供实例区使用

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script type="text/javascript">javascript">// 创建一个类class Person {// 构造器方法constructor(name, age) {// 构造器中的this是谁?—— 类的实力对象this.name = namethis.age = age}// 一般方法:除了构造器以外的自定义方法speak() {// speak 方法放在了哪里?——类的原型对象上,供实例使用// 通过 Person 实例调用 speak 时,speak 中的 this 就是 Person 实例console.log(`我叫${this.name},今年${this.age}`)}// 原型链:当查找一个不存在于自身的原型时,会查找原型,一层一层找下去,直到找到 Object,这就是一个原型链}// 创建一个实例对象let p1 = new Person('tom', 20)console.log(p1)p1.speak()// 创建一个 student 类继承于Person类class student extends Person {constructor(name, age, grade) {super(name, age)this.grade = grade}// 重写从父类继承过来的方法speak() {console.log(`我叫${this.name},今年${this.age} 岁,我正在读${this.grade}`,)}study() {// speak 方法放在了哪里?——类的原型对象上,供实例使用// 通过 student 实例调用 speak 时,speak 中的 this 就是 student 实例console.log('我学习很用心')}}let s1 = new student('小张', 15, '九年级')console.log(s1)s1.speak()s1.study()</script></body>
</html>

3、类式组件

_ 执行了 ReactDOM.render(, … 之后,发生了什么?
_ 1.React 解析组件标签,找到了 MyComponent 组件
_ 2.发现组件是使用类定义的,随后 new 出来该类的实例,并通过该实例调用到 原型上的 render 方法。
_ 3.将 render 返回的虚拟 DOM 转为真实 DOM,随后呈现在页面中

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>类式组件</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">//   1、创建类式组件class MyComponent extends React.Component {render() {// render 是放在哪里的?—— MyComponent 的原型对象上,供实例使用//  render  中的this 是谁?—— MyComponent 的实例对象。MyComponent 组件的实例对象return <h2>我是用类定义的组件(适用于【复杂组件】)的定义</h2>}}// 2、渲染组件到页面ReactDOM.render(<MyComponent />, document.getElementById('test'))/*** 执行了 ReactDOM.render(<MyComponent/>, .... 之后,发生了什么?* 1.React 解析组件标签,找到了 MyComponent 组件* 2.发现组件是使用类定义的,随后new 出来该类的实例,并通过该实例调用到 原型上的 render 方法。* 3.将render 返回的虚拟 DOM 转为真实 DOM,随后呈现在页面中*/</script></body>
</html>

4、简单组件和复杂组件

简单组件:没有状态
复杂组件:有状态(state)的组件

例子:
人 状态 影响 行为
组件 状态 驱动 数据

二、组件实例的三大核心属性 1:state

1、例子,点击文字切换 凉爽和炎热

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>切换天气</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class Weather extends React.Component {// 构造器调用几次?—— 1次constructor(props) {console.log('constructor')super(props)// 借用构造器初始化 状态this.state = {isHot: false,wind: '微风',}// bind 改变 this 的指向并且返回一个新函数this.changeWeather = this.changeWeather.bind(this) // 解决类中方法局部严格模式导致 this 为 undefined 问题}// render调用几次?—— 1 + n 次, 1 是初始化的那次,  n 是状态更新的次数render() {console.log('render')// 读取状态let { isHot, wind } = this.stateconsole.log(this, this.state)return (<h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}, {wind}</h1>)}// changeWeather调用几次?—— 点几次调几次changeWeather() {// changeWeather 放在那里?—— Weather 的原型对象,供实例使用// 由于changeWeather 是作为 onClick 的回调,所以不是通过实例调用的,是直接调用// 类中的方法 默认开启了局部的严格模式,所以 changeWeather 中的 this 是 undefined// console.log('点击文字', this) // 为什么this 是 undefined?——类中的方法 默认开启了局部的严格模式,所以 changeWeather 中的 this 是 undefined// 获取原来的 isHot 的值let { isHot } = this.state// 严重注意:状态(State)里面的数据不能直接更改, 要借助一个内置的 API 去更改// this.state.isHot = !isHot // 这行就是直接更改!这是错误写法// 严重注意: 状态(state)必须通过 setState 进行更改,且更新是一种合并,不是替换this.setState({ isHot: !isHot })console.log(isHot, this)}}// 2、渲染组件到页面// ReactDOM.render(组件,容器)ReactDOM.render(<Weather />, document.getElementById('test'))</script></body>
</html>

为什么要写构造器?—— 为了初始化状态和改变 this 的指向
setState 更改数据时候是合并还是替换?—— 是合并,不是替换
constructor 构造器调用几次?—— 1 次
render 调用几次?—— 1 + n 次, 1 是初始化的那次, n 是状态更新的次数
changeWeather 调用几次?—— 点几次调几次
类中的方法 默认开启了局部的严格模式, this 为 undefined

onClick={changeTitle} :指定函数,点击的时候 react 帮你调用函数,不可以加小括号,如果添加了页面渲染完毕 react 就会直接调用函数

1.1 复习–原生事件绑定方式
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>原生事件绑定</title></head><body><button id="btn1">按钮1</button><button id="btn2">按钮2</button><button onclick="javascript language-javascript">demo()">按钮3</button><script type="text/javascript">javascript">let btn1 = document.getElementById('btn1')btn1.addEventListener('click',() => {alert('按钮1 被点击了')},false,)let btn2 = document.getElementById('btn2')btn2.onclick = () => {alert('按钮2 被点击了')}function demo() {alert('按钮3 被点击了')}</script></body>
</html>
1.2 复习–类中的方法 this 指向

类中所定义的方法 局部都开启了严格模式

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>3_类中的方法this 指向.html</title></head><body><script type="text/javascript">javascript">class Person {constructor(name, age) {this.name = namethis.age = age}// 类中所定义的方法 局部都开启了严格模式speak() {// speak 方法放在了哪里?—— 类的原型对象上,供实例使用// 通用 Person 实例调用 speak 时,speak 中的 this 就是 Person 实例console.log(this)}}let p1 = new Person('Tom', 20)p1.speak() // 通过实例调用 speak 方法const x = p1.speak // 函数的直接调用x() // undefined : 类中所定义的方法 局部都开启了严格模式,直接调用 this 是 undefined</script></body>
</html>
1.3 类的复习—类中添加属性
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script type="text/javascript">javascript">class Car {constructor(name, price) {this.name = namethis.price = price}// 类中可以直接写赋值语句,如下的代码的含义是: 给Car 的实例对象添加一个属性,名为 wheel,值为 4wheel = 4}let c1 = new Car('奔驰C63', 199)let c2 = new Car('奔驰111C63', 100)console.log(c2)console.log(c1)</script></body>
</html>
1.3 例子的简写。state 的简写
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>state 的简写</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class Weather extends React.Component {state = {isHot: false,wind: '微风',}render() {// console.log(this)let { isHot, wind } = this.statereturn (<h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}, {wind}</h1>)}// 以下代码相当于 changeWeather = this.changeWeather.bind(this)// 此处不要写普通函数。需要写箭头函数:因为箭头函数没有自己的this,会找外层的 thischangeWeather = () => {console.log(this)let { isHot } = this.statethis.setState({ isHot: !isHot })}}// 2、渲染组件到页面ReactDOM.render(<Weather />, document.getElementById('test'))</script></body>
</html>

2、理解

1)state 是组件对象最重要的属性,值是对象(可以包含多个 key-value 的组合)—— 因为 setState 更改状态的时候接收的是 对象
2)组件被称为“状态机”, 通过更新组件的 state 来更新对应的页面显示(重新渲染组件)

3、强烈注意

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

三、组件实例的三大核心属性 2:props

1、例子:自定义用来显示一个人员信息的组件

1.1 要求:

1)姓名必须指定,且为字符串类型
2)性别为字符串类型,如果性别没有指定,默认为男
3)年龄必须指定,且为数字类型

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>props基本使用</title></head><body><div id="test"></div><div id="test1"></div><div id="test2"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class Person extends React.Component {render() {console.log(this)let { name, gender, age } = this.propsreturn (<ul><li>姓名:{name}</li><li>性别:{gender}</li><li>年龄:{age}</li></ul>)}}// 2、渲染组件到页面// ReactDOM.render(组件,容器)const p = { name: 'Tom54', gender: '男', age: 20 }// {...p} 一般来说展开运算符不能展开对象,但是 在 babel 和react 中可以用来展开对象作批量属性到组件上ReactDOM.render(<Person {...p} />, document.getElementById('test'))ReactDOM.render(<Person name="jerry" gender="女" age={18} />,document.getElementById('test1'),)ReactDOM.render(<Person name="jack" gender="男" age={5} />,document.getElementById('test2'),)</script></body>
</html>
1.2 复习–展开运算符(…)

用法:
1)展开一个数组
2)连接数组
3)在函数中使用
4)字面量的形式复制一个对象,是深克隆
5)合并对象(复制对象的同时修改属性)

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script type="text/javascript">javascript">let arr = [1, 2, 3, 4, 5]console.log(...arr) // 1、展开一个数组let arr2 = [11, 12, 14, 16]let arr3 = [...arr, ...arr2] // 2、连接数组// 3、在函数中使用function sum(...numbers) {console.log('@', numbers)// 实现方式1:// let total = 0// numbers.forEach((el) => {//   total += el// })// return total//实现求和方法2return numbers.reduce((preValue, currentValue) => {return preValue + currentValue})}console.log(sum(1, 2, 5)) //let p = { name: 'Tom', page: 15 }let p2 = { ...p } // 4、字面量的形式复制一个对象,是深克隆// console.log(...p) // 报错,展开运算符不能展开对象p.name = 'jack'console.log(p2.name)//5、合并对象(复制对象的同时修改属性)let p3 = { ...p, name: 'Jerry' }console.log(p3.name)</script></body>
</html>
1.3 对传递的属性(props)进行校验

React 15.x 之前 React.PropTypes 有维护
React 16.x 后 React.PropTypes 被废弃

<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>props基本使用</title></head><body><div id="test"></div><div id="test1"></div><div id="test2"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes --><script type="text/javascript" src="../js/prop-types.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class Person extends React.Component {render() {let { name, gender, age } = this.propsreturn (<ul><li>姓名:{name}</li><li>性别:{gender}</li><li>年龄:{age + 1}</li></ul>)}}// react 识别propTypes属性就是加规则// 对标签属性进行类型、必要性的限制Person.propTypes = {name: PropTypes.string.isRequired, // 姓名必须指定,且为字符串类型gender: PropTypes.string, // 性别为字符串类型age: PropTypes.number, //年龄为数字类型speak: PropTypes.func, // 限制 speak 为函数}// 指定默认标签属性值Person.defaultProps = {gender: '男',age: 18,}// 2、渲染组件到页面// ReactDOM.render(组件,容器)const p = { name: 'Tom54', age: 20 }ReactDOM.render(<Person {...p} />, document.getElementById('test'))ReactDOM.render(<Person name={12} gender="女" age={18} speak="1" />,document.getElementById('test1'),)ReactDOM.render(<Person name="jack" gender="男" />,document.getElementById('test2'),)function speak() {console.log('说话了')}</script></body>
</html>
1.4 复习-- 类的关键字 static
javascript">class Car {constructor(name, price) {this.name = namethis.price = price}// 类中可以直接写赋值语句,如下的代码的含义是: 给Car 的实例对象添加一个属性,名为 wheel,值为 4wheel = 4a = 1static demo = 100 // 添加一个属性给 类
}
let c1 = new Car('奔驰C63', 199)
console.log(c2)
console.log(c2.demo())
1.5 props 简写方式
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>props基本使用</title></head><body><div id="test"></div><div id="test1"></div><div id="test2"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes --><script type="text/javascript" src="../js/prop-types.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class Person extends React.Component {render() {let { name, gender, age } = this.props// this.props.name = '哈哈哈'// 此行代码会报错,因为 props 是只读的return (<ul><li>姓名:{name}</li><li>性别:{gender}</li><li>年龄:{age + 1}</li></ul>)}// 对标签属性进行类型、必要性的限制static propTypes = {name: PropTypes.string.isRequired, // 姓名必须指定,且为字符串类型gender: PropTypes.string, // 性别为字符串类型age: PropTypes.number, //年龄为数字类型speak: PropTypes.func, // 限制 speak 为函数}// 指定默认标签属性值static defaultProps = {gender: '男',age: 18,}}// 2、渲染组件到页面// ReactDOM.render(组件,容器)const p = { name: 'Tom54', age: 20 }ReactDOM.render(<Person {...p} />, document.getElementById('test'))ReactDOM.render(<Person name={12} gender="女" age={18} speak={speak} />,document.getElementById('test1'),)ReactDOM.render(<Person name="jack" gender="男" />,document.getElementById('test2'),)function speak() {console.log('说话了')}</script></body>
</html>

构造器 constructor
在 React 组件挂载之前,会调用它的构造函数。在为 React.Component 子类实现构造函数时,应在其他语句之前调用 super(props), 否则, this.props 在构造函数中可能会出现未定义的 bug

构造器是否接收 props,是否传递给 super, 取决于:是否希望在构造器中通过 this 访问 props (几乎不用)

1.6 函数式组件使用 props。三大属性中函数式组件仅能使用 props
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>简写</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes --><script type="text/javascript" src="../js/prop-types.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件function Person(props) {let { name, gender, age } = propsreturn (<ul><li>姓名:{name}</li><li>性别:{gender}</li><li>年龄:{age + 1}</li></ul>)}Person.propTypes = {name: PropTypes.string.isRequired, // 姓名必须指定,且为字符串类型gender: PropTypes.string, // 性别为字符串类型age: PropTypes.number, //年龄为数字类型}Person.defaultProps = {gender: '男',age: 18,}// 2、渲染组件到页面// ReactDOM.render(组件,容器)const p = { name: 'Tom', age: 15, gender: '女' }ReactDOM.render(<Person {...p} />, document.getElementById('test'))</script></body>
</html>

2、理解

1)每个组件对象都会有 props(properties 的简写)属性
2)组件标签的所有属性都保存在 props 中

2、理解

1)每个组件对象都会有 props(properties 的简写)属性
2)组件标签的所有属性都保存在 props 中

3、作用

1)通过标签属性从组件外向组件内传递变化的数据
2)注意:组件内部不要修改 props 数据

4、编码操作

1)内部读取某个属性值

javascript">this.props.name

2)对 props 中的属性值进行类型限制和必要性限制
第一种方式 (React v15.5 开始已经弃用)

javascript">Person.propTypes = {name: React.PropTyes.string,
}

第二种方式 (新)
使用 prop-types 库进行限制(需要引入 prop-types 库)

javascript">Person.propTypes = {name: React.PropTyes.string,
}

3)扩展属性:将对象的所有属性通过 props 传递

javascript"><Person {...param} />

4)默认属性值

javascript">Person.defaultProps = {gender: '男',age: 18,
}

5)组件类的构造函数(项目中基本不用)

javascript">constructor(props) {super(props)console.log(props) // 打印所有属性
}

四、组件实例的三大核心属性 3:refs 与事件处理

1、例子

1.1 需求:自定义组件,功能说明如下:

1)点击按钮,提示第一个输入框中的值
2)当第 2 个输入框失去焦点时,提示这个输入框中的值

1.2 过时 API :String 类型的 Refs

string 类型的 ref 存在一些效率问题。已过时会在未来的版本被移除

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>refs 与事件处理</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes --><script type="text/javascript" src="../js/prop-types.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class MyComponent extends React.Component {render() {return (<div><input ref="input1" type="text" placeholder="点击按钮提示数据" />&nbsp; &nbsp;<button onClick={this.showData}>点我提示左侧的数据</button>&nbsp; &nbsp;<inputref="input2"type="text"placeholder="失去焦点提示数据"onBlur={this.blurInput}/></div>)}// 展示左侧输入框的数据showData = () => {console.log('点击按钮提示数据', this.refs.input1.value)}blurInput = () => {console.log('失去焦点提示数据:', this.refs.input2.value)}}// 2、渲染组件到页面// ReactDOM.render(组件,容器)ReactDOM.render(<MyComponent />, document.getElementById('test'))</script></body>
</html>
1.3 回调函数形式的 ref

如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null, 然后第二次会传输参数 DOM 元素。
这是因为在每次渲染时创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。
通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的

内联函数方式

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>refs 与事件处理</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes --><script type="text/javascript" src="../js/prop-types.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class MyComponent extends React.Component {render() {return (<div><inputref={(currentNode) => (this.input1 = currentNode)}type="text"placeholder="点击按钮提示数据"/>&nbsp; &nbsp;<button onClick={this.showData}>点我提示左侧的数据</button>&nbsp; &nbsp;<inputref={(currentNode) => (this.input2 = currentNode)}type="text"placeholder="失去焦点提示数据"onBlur={this.blurInput}/></div>)}// 展示左侧输入框的数据showData = () => {let { input1 } = thisconsole.log(input1.value)}blurInput = () => {let { input2 } = thisconsole.log(input2.value)}}// 2、渲染组件到页面// ReactDOM.render(组件,容器)ReactDOM.render(<MyComponent />, document.getElementById('test'))</script></body>
</html>

回调函数的 ref 中 回调函数执行次数?—— 更新(触发 render 时)过程中会被执行两次,第一次传入参数 null, 然后第二次会传输参数 DOM 元素
jsx 中注释代码{//}**

通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>refs 与事件处理</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes --><script type="text/javascript" src="../js/prop-types.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class MyComponent extends React.Component {state = {isHot: true,}render() {let { isHot } = this.statereturn (<div><h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2>{/*<inputref={(currentNode) => {this.input1 = currentNodeconsole.log('@@', currentNode)}}type="text"placeholder="点击按钮提示数据"/>*/}<inputref={this.saveInput}type="text"placeholder="点击按钮提示数据"/>&nbsp; &nbsp;<button onClick={this.showData}>点我提示数据</button>&nbsp; &nbsp;<button onClick={this.changeWeather}>点我切换天气</button></div>)}saveInput = (currentNode) => {this.input1 = currentNodeconsole.log(this)}// 展示左侧输入框的数据showData = () => {let { input1 } = thisconsole.log(input1.value)}// 切换天气changeWeather = () => {let { isHot } = this.statethis.setState({ isHot: !isHot })}}// 2、渲染组件到页面// ReactDOM.render(组件,容器)ReactDOM.render(<MyComponent />, document.getElementById('test'))</script></body>
</html>
1.4 createRef (官方推荐写法)

React.createRef 调用后可以返回一个容器,该容器可以存储被 ref 所表示的节点,该容器是 “专人专用” 的(只能存放一个 ref),后面的会覆盖前面的

缺点:每一个 ref 都需要创建容器

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>createRef</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes --><script type="text/javascript" src="../js/prop-types.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class MyComponent extends React.Component {/*** React.createRef调用后可以返回一个容器,该容器可以存储被 ref 所表示的节点*/myRef = React.createRef()myRef2 = React.createRef()render() {return (<div><inputref={this.myRef}type="text"placeholder="点击按钮提示数据"/>&nbsp; &nbsp;<button ref={this.myRef} onClick={this.showData}>点我提示数据</button>&nbsp; &nbsp;<inputref={this.myRef2}type="text"onBlur={this.showData2}placeholder="失去焦点提示数据"/></div>)}// 展示左侧输入框的数据showData = () => {let { current } = this.myRefconsole.log(current.value)}showData2 = () => {let { current } = this.myRef2console.log(current.value)}}// 2、渲染组件到页面// ReactDOM.render(组件,容器)ReactDOM.render(<MyComponent />, document.getElementById('test'))</script></body>
</html>

2、理解

组件内的标签可以定义 ref 属性来标识自己

3、编码

1)字符串形式的 ref

javascript"><input ref="input2" type="text" />

2)回调形式的 ref

javascript"><inputref={(currentNode) => {this.input1 = currentNode}}
/>

3)createRef 创建 ref 容器

javascript">myRef = React.createRef()
<inputref={this.myRef}type="text"
/>

需要避免过度使用 ref

4、事件处理

1)通过 onXxx 属性指定事件处理函数(注意大小写)
a、React 使用的是自定义(合成)事件,而不是使用的原生 DOM 事件 —— 为了更好的兼容性
b、React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素)—— 为了高效
事件委托的原理是事件冒泡
2)通过 event.target 得到发生事件的 DOM 元素对象 —— 不要过度使用 ref

当发生事件的元素就是操作的元素,就可以省略 ref , 使用 event.target 获取即可

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>createRef</title></head><body><div id="test"></div><!-- 引入 react 核心库 --><script type="text/javascript" src="../js/react.development.js"></script><!-- 引入 react-dom,用于支持 react 操作DOM --><scripttype="text/javascript"src="../js/react-dom.development.js"></script><!-- 引入babel, 用于将 jsx 转为 js --><script type="text/javascript" src="../js/babel.min.js"></script><!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes --><script type="text/javascript" src="../js/prop-types.js"></script><!-- 此处一定要写babel --><script type="text/babel">javascript">// 1、创建组件class MyComponent extends React.Component {/*1)通过 onXxx 属性指定事件处理函数(注意大小写)a、React 使用的是自定义(合成)事件,而不是使用的原生 DOM 事件b、React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素)2)通过 event.target 得到发生事件的 DOM 元素对象*/// 创建 ref 容器myRef = React.createRef()myRef2 = React.createRef()render() {return (<div><inputref={this.myRef}type="text"placeholder="点击按钮提示数据"/>&nbsp; &nbsp;<button ref={this.myRef} onClick={this.showData}>点我提示数据</button>&nbsp; &nbsp;<inputtype="text"onBlur={this.showData2}placeholder="失去焦点提示数据"/></div>)}// 展示左侧输入框的数据showData = () => {let { current } = this.myRefconsole.log(current.value)}showData2 = (event) => {console.log(event.target.value)}}// 2、渲染组件到页面// ReactDOM.render(组件,容器)ReactDOM.render(<MyComponent />, document.getElementById('test'))</script></body>
</html>

http://www.ppmy.cn/embedded/100752.html

相关文章

Redis篇一:初识Redis

文章目录 前言1. 初始Redis2. MySQL VS Redis3. 什么是分布式系统&#xff08;也是一种处理大量数据时的处理方式&#xff09;3.1 单机架构3.2 数据库与应用服务分离3.3 负载均衡3.4 数据库读写分离3.5 引入缓存&#xff08;Redis&#xff09;3.6 数据库分库分表3.7 引入微服务…

网络udp及ipc内存共享

大字符串找小字符串 调试 1. 信号处理函数注册&#xff1a;•一旦使用 signal 函数注册了信号处理函数&#xff0c;该函数就会一直有效&#xff0c;直到程序结束或者显式地取消注册。2. 注册多次的影响&#xff1a;•如果多次注册同一信号的处理函数&#xff0c;最后一次注册的…

Java RPC、Go RPC、Node RPC、Python RPC 之间的互相调用

Java RPC、Go RPC、Node RPC、Python RPC 之间的互相调用是完全可以实现的&#xff0c;但需要满足一些条件和依赖于特定的工具和协议。以下是如何实现不同语言之间的RPC互相调用的详细解释&#xff1a; 1. 使用通用协议和标准&#xff1a;gRPC gRPC 是一个高性能、开源的RPC框…

SSRF漏洞——pikachu

环境搭建 pikachu文件如下&#xff1a; 通过百度网盘分享的文件&#xff1a;pikachu-master.zip 链接&#xff1a;https://pan.baidu.com/s/1HuV2llJzx1c7Ii6u-r4s3Q?pwdqwer 提取码&#xff1a;qwer 解压至小皮WWW文件夹下&#xff0c;进入config.inc.php中修改MySQL名字…

深信达反向沙箱:构筑内网安全与成本效益的双重防线

# 深信达反向沙箱&#xff1a;内网安全与成本控制的双重保障 在数字化时代&#xff0c;企业面临着日益复杂的网络安全挑战。内网安全尤其关键&#xff0c;因为它涉及到企业的核心数据和运营。深信达的反向沙箱技术&#xff0c;作为一种创新的安全解决方案&#xff0c;为政企单…

基于Android的运动记录APP设计与实现(论文+源码)_kaic

摘要 随着人们生活水平和生活质量的提高&#xff0c;人们越来越关注自己的身体健康。而跑步成为人们最受欢迎的运动方式&#xff0c;运动软件可以在人们锻炼身体的时候提供极大的帮助。本文针对运动轨迹和计步&#xff0c;设计一款基于Android 平台的运动软件。本系统通过使用百…

【OCPP】ocpp1.6协议第5.14 Reset章节的介绍及翻译

目录 5.14 重置Reset-概述 概述 消息格式 操作流程 重置类型 消息示例 错误处理 注意事项 安全性 5.14 重置Reset-原文译文 5.14 重置Reset-概述 在OCPP 1.6协议中,第5.14章节“Reset”主要讲述了中央系统(CSMS, Central System)如何向充电站(CS, Charge Statio…

培训第三十二天(学习playbook-roles,脚本创建数据库和表,mycat读写分离)

上午 1、roles&#xff08;角色&#xff09;介绍 roles(⻆⾊): 就是通过分别将variables, tasks及handlers等放置于单独 的⽬录中,并可以便捷地调⽤它们的⼀种机制。 假设我们要写⼀个playbook来安装管理lamp环境&#xff0c;那么这个 playbook就会写很⻓。所以我们希望把这…

ES详细使用!Elasticsearch实现索引操作,增删改查,批处理

要想知道ES怎么具体实现对数据的操作&#xff0c;我们首先应该了解一下什么叫做restful编码风格&#xff0c;因为es的具体操作都是restful风格的。 1.RESTful风格 RESTful 是一种软件架构风格&#xff0c;用于创建可扩展的网络服务。它使用 HTTP 方法&#xff08;如 GET、POS…

C++竞赛初阶L1-13-第五单元-循环嵌套(29~30课)538: T456457 第 n 小的质数

题目内容 输入一个正整数 n&#xff0c;求正整数范围中第 n 小的质数。 输入格式 一个不超过 30000 的正整数 n。 输出格式 第 n 小的质数。 样例 1 输入 10 全部程序代码&#xff1a; #include<bits/stdc.h> using namespace std; int main() {long long n,i;ci…

StarRocks 存算分离数据回收原理

前言 StarRocks存算分离表中&#xff0c;垃圾回收是为了删除那些无用的历史版本数据&#xff0c;从而节约存储空间。考虑到对象存储按照存储容量收费&#xff0c;因此&#xff0c;节约存储空间对于降本增效尤为必要。 在系统运行过程中&#xff0c;有以下几种情况可能会需要删…

Linux运维、Windows运维常用命令,保存起来当手册用

文章目录 一、centos基本命令1、升级内核到最新版本2、文件句柄数限制优化3、ssh、sftp、scp等远程命令4、find文件查找5、vi命令 二、windows常用操作 一、centos基本命令 1、升级内核到最新版本 # 1、查看内核版本 [rootlocalhost ~]# cat /etc/centos-release CentOS Linu…

关于Spring Boot的自动配置

目录 1.EnableAutoConfiguration注解 2.SpringBootConfiguration注解 3.Import注解 4.spring.factories 5.总结 &#xff08;1&#xff09;EnableAutoConfiguration &#xff08;2&#xff09;AutoConfigurationImportSelector &#xff08;3&#xff09; SpringFactoriesLoade…

G1处理器GC调优常用参数详解

mixGC触发机制&#xff1a; G1 垃圾收集器在执行垃圾收集时&#xff0c;会根据不同的情况选择不同的垃圾收集策略&#xff0c;其中 "Mixed GC" 是一种比较复杂的策略&#xff0c;用于回收整个堆内存中的垃圾。 G1 垃圾收集器执行 Mixed GC 的时机通常取决于以下几个…

【Python进阶(十)】——Matplotlib基础可视化

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

Java泛型机制详解

引入泛型的原因 泛型的本质是为了参数化类型&#xff08;在不创建新的类型的情况下&#xff0c;通过泛型指定的不同类型来控制形参具体限制的类型&#xff09;。也就是说在泛型使用过程中&#xff0c;操作的数据类型被指定为一个参数&#xff0c;这种参数类型可以用在类、接口…

一、HTML5知识点精讲

一、HTML5介绍 html是用来描述网页的一种语言&#xff08;就是写网页的一种语言&#xff09;。 它和CSS&#xff0c;JS称为网页三要素。 HTML负责把元素简单呈现在网页上&#xff0c;是网页的身体CSS负责给网页元素添加各种样式&#xff0c;是网页的衣服JS负责实现各种动态、…

ShellSweepPlus 介绍:开源 Web Shell 检测

ShellSweepPlus 概述 ShellSweepPlus是一款开源工具,旨在帮助安全团队检测潜在的 Web Shell。它是 ShellSweep 的增强版 Webshell 的威胁 Web shell 对组织构成重大威胁,因为它们为攻击者提供了对受感染 Web 服务器的未经授权的访问和控制。攻击者可以利用这些 shell 来:…

6.InnoDB引擎

InnoDB引擎 1.逻辑存储结构2.架构2.1内存架构2.2 磁盘结构 3.事务原理3.1 事务3.2 redo log3.3undo log 4.MVCC4.1MVCC 基本概率14.2 实现原理 1.逻辑存储结构 2.架构 2.1内存架构 2.2 磁盘结构 create tablespace mytest add datafile mytest.idb engineinnodb;后台线程 mys…

用 postman 的时候如何区分服务器还是自己的问题?

“首先&#xff0c;可以通过请求的目标地址来判断。如果目标地址是已知的服务器地址&#xff0c;那很可能是在与服务器进行交互。而如果目标地址指向本地的特定端口或 IP 地址&#xff0c;比如 127.0.0.1 或 localhost&#xff0c;那就可能是在测试本地的服务。 其次&#xff…