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

ops/2024/9/20 7:14:39/ 标签: 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/ops/97239.html

相关文章

Qt鼠标键盘事件监听

普通的程序中. 鼠标事件监听 要监听鼠标事件&#xff0c;你可以使用QMouseEvent类&#xff0c;它提供了多种类型的鼠标事件&#xff0c;如QMouseEvent::MouseButtonPress、QMouseEvent::MouseButtonRelease、QMouseEvent::MouseMove等。 但是离开程序后就很难监听到&#xff0c…

x264 编码器 AArch64汇编系列:帧内预测函数

x264 汇编介绍 关于 x264 汇编介绍可以参考:x264 编码器汇编模块介绍关于 x264 AArch64汇编函数介绍可以参考:x264 编码器 AArch64 汇编函数模块关系分析帧内预测AArch64 汇编函数 在进行帧内预测编码过程,需要对各种分块模式进行模式预测。汇编函数关系和原理图:【Plane 模…

如何在Spring Boot应用中加载和使用TensorFlow模型

在Spring Boot应用中加载和使用TensorFlow模型&#xff0c;‌可以通过以下步骤实现&#xff1a;‌ ‌创建Spring Boot项目‌&#xff1a;‌首先&#xff0c;‌使用Spring Initializr创建一个新的Spring Boot项目&#xff0c;‌并添加Spring Web依赖。‌‌添加TensorFlow依赖‌…

asp.net MVC 根据菜单树类别不同,动态加载视图

在 ASP.NET MVC 中&#xff0c;根据菜单树的类别动态加载不同的视图&#xff0c;可以通过以下步骤实现&#xff1a; 目录 1. 创建菜单模型 2. 构建菜单树 3. 动态加载视图 4. 创建部分视图 5. 根据类别动态加载部分视图 6. 使用 Ajax 动态加载&#xff08;可选&#xff…

【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(十四)

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

算法的学习笔记—栈的压入、弹出序列(牛客JZ31)

&#x1f600;前言 栈&#xff08;Stack&#xff09;是一种常见的数据结构&#xff0c;具有“后进先出”的特性。在实际应用中&#xff0c;我们常常需要验证一组操作是否符合栈的特性。本文将探讨如何通过编程判断一个给定的弹出序列是否可以由另一个给定的压入序列生成&#x…

如何将 Windows 11/10/8/7 克隆到另一台计算机

为什么需要将 Windows克隆到新计算机 “我有一台新笔记本电脑来替换我的旧电脑&#xff0c;因为它运行几年后变得越来越慢。我现在面临的问题是如何让 Windows 10、程序和文件与旧 PC 保持相同。我不想重新安装 Windows 和应用程序。有没有快速简便的方法可以做到这一点&#…

PyTorch 基础学习

文章索引&#xff1a; PyTorch 基础学习&#xff08;1&#xff09; - 快速入门 PyTorch 基础学习&#xff08;2&#xff09;- 张量 Tensors PyTorch 基础学习&#xff08;3&#xff09; - 张量的数学操作 PyTorch 基础学习&#xff08;4&#xff09;- 张量的类型 PyTorch 基础学…

汽车EDI: NAVISTAR EDI对接

Navistar International Corporation 是一家美国商用车辆制造公司&#xff0c;总部位于伊利诺伊州的Lisle。公司以生产中型和重型卡车、公共汽车、柴油发动机和底盘闻名&#xff0c;其产品广泛应用于运输、建筑、和农业等行业。Navistar 的历史可以追溯到1831年&#xff0c;由国…

初识spring security (一),一文弄懂默认配置

一、简单导入依赖 1、导入pom <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.2</version></parent><modelVersion>4.0.0</modelVersion&g…

定制开发AI智能名片商城小程序:融合销售策略与个人魅力的营销新路径

摘要&#xff1a;在数字化时代&#xff0c;营销策略的创新与个性化成为企业脱颖而出的关键。本文探讨了如何通过定制开发AI智能名片商城小程序&#xff0c;结合销售策略与个人魅力&#xff0c;实现用户心甘情愿购买产品的目标。通过分析用户行为、心理需求及市场趋势&#xff0…

django之反向关系查询<related_model>_set/related_name

假设有两个模型&#xff1a;Author和Post&#xff0c;其中Post模型通过ForeignKey字段与Author模型相关联。 模型定义 from django.db import modelsclass Author(models.Model):first_name models.CharField(max_length30)last_name models.CharField(max_length30)class …

src资产收集心得

src平台的收录公告 ● 有的src平台公告中写着不要哪些站的洞得看清楚不然白忙活 ● 给你的是根域还是业务范围 收集方法/工具 ● oneforall(功能强大你需要配置api能配就配下&#xff0c;比较耗时) ● 灯塔&#xff08;本人不用&#xff09; ● layer ● fofa、quake、hunte…

EmguCV学习笔记 C# 5.2 仿射变换

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

vba自动发送邮件的基础步骤?有哪些流程?

vba自动发送邮件如何设置&#xff1f;vba自动发送邮件的技巧&#xff1f; 如果你想节省时间&#xff0c;提高工作效率&#xff0c;学会如何使用VBA自动发送邮件是一个非常有用的技能。AokSend将为你介绍VBA自动发送邮件的基础步骤&#xff0c;并通过简单的分段来详细讲解。 v…

[数据集][目标检测]夜间老鼠检测数据集VOC+YOLO格式316张1类别+视频文件1个

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;316 标注数量(xml文件个数)&#xff1a;316 标注数量(txt文件个数)&#xff1a;316 标注类别…

精益管理|介绍一本专门研究防错法(Poka-Yoke)的书

在现代制造业中&#xff0c;如何确保产品在每个生产环节中不出现错误是企业追求的目标之一。而实现这一目标的关键技术之一就是防错法&#xff08;Poka-Yoke&#xff09;。作为一种简单而有效的精益管理、六西格玛管理工具&#xff0c;防错法帮助企业避免因人为错误或工艺不当导…

共享打印机修复工具哪个好_2024年共享打印机修复工具推荐

共享打印机修复工具哪个好&#xff1f;最近几年使用过共享打印机的小伙伴遇到各种共享错误&#xff0c;出现0x00000709和0x0000011b访问共享打印机问题&#xff0c;各种打印机修复工具也有&#xff0c;下面小编就给大家介绍共享打印机修复工具哪个好用分析。 共享打印机修复工具…

用Python实现生信分析——序列搜索和比对工具详解

1. 什么是序列搜索和比对工具&#xff1f; 序列搜索和比对工具在生物信息学中用于在大型序列数据库中搜索与查询序列相似的序列&#xff0c;并进行比对分析。这些工具可以帮助研究人员识别与目标序列相关的已知序列&#xff0c;从而推测其功能、结构和进化关系。 常见的序列搜…

2024零基础转行做程序员,选什么语言更好就业?

零基础转行做程序员&#xff0c;选什么语言更好就业&#xff0c;未来的发展前景更好&#xff1f; 这个问题困扰了不少想转行的同学。有人说Python简单好上手&#xff0c;有人说Java就业机会多&#xff0c;有人说C薪资高&#xff0c;到底该怎么选&#xff1f; 其实各个语言的发…