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

本文主要是介绍02_React面向组件编程--基本使用与理解、组件实例的三大核心属性与事件处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

    • 一、基本理解与使用
      • 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">//   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">// 创建一个类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">//   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">// 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="demo()">按钮3</button><script type="text/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">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">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">// 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">// 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">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">// 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
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">// 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">// 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)内部读取某个属性值

this.props.name

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

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

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

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

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

<Person {...param} />

4)默认属性值

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

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

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">// 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">// 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">// 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">// 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

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

2)回调形式的 ref

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

3)createRef 创建 ref 容器

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">// 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>

这篇关于02_React面向组件编程--基本使用与理解、组件实例的三大核心属性与事件处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1092735

相关文章

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

python使用try函数详解

《python使用try函数详解》Pythontry语句用于异常处理,支持捕获特定/多种异常、else/final子句确保资源释放,结合with语句自动清理,可自定义异常及嵌套结构,灵活应对错误场景... 目录try 函数的基本语法捕获特定异常捕获多个异常使用 else 子句使用 finally 子句捕获所

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

C#中lock关键字的使用小结

《C#中lock关键字的使用小结》在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时,其他线程无法访问同一实例的该代码块,下面就来介绍一下lock关键字的使用... 目录使用方式工作原理注意事项示例代码为什么不能lock值类型在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时