React组件 (一)
在React中定义组件
函数式组件
函数式组件(用函数定义的组件)比较简单一般用于静态没有交互事件内容的组件页面
// 1、创建函数式组件 (组件是代码和资源的结合)
function MyComponent(){
console.log(this) // 此处的this是undefin 因为babel翻译后开启了严格模式
return <h1>我是函数定义的组件(适应于【简单组件】的定义)</h1>
}
// 2、渲染到页面上
ReactDOM.render(<MyComponent />,document.getElementById('test'))
注意
-
首字母必须大写
-
函数必须有返回值
-
ReactDOM.render第一个参数为组件标签(要闭合,必须有结束标签)
执行了 ReactDOM.render(,document.getElementById('test')) 之后,发生了什么?(渲染函数式组件标签的基本流程)
-
React解析组件标签,找到了MyComponent组件。
-
发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
类式组件
类式组件(用类定义的组件)又称为动态组件,一般用于有交互事件或数据修改的组件页面
// 1、创建类式组件 (组件是代码和资源的结合)
class MyComponent extends React.Component {
render(){
console.log('render中的this:',this);
return <h1>我是类式组件(适应于【复杂组件】的定义)</h1>
}
}
// 2、渲染到页面上
ReactDOM.render(<MyComponent />,document.getElementById('test'))
-
render是放在哪里了? - 类MyComponent的原型对象上,供实例使用
-
render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。
注意
-
必须继承父类
-
必须写render
-
render必须有返回值
执行了 ReactDOM.render(,document.getElementById('test')) 之后,发生了什么?渲染类式组件标签的基本流程
-
React解析组件标签,找到了MyComponent组件。
-
发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
-
将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
组件实例的三大属性 1 : state
复杂组件:有状态(state)的组件
简单组件:没有状态的组件
一个demo
需求: 自定义组件, 功能说明如下
- 显示h1标题, 初始文本为: 你喜欢我
- 点击标题更新为: 我喜欢你
第一步:创建一个自定义组件,显示h1标题,初始文本是:你喜欢我
// 创建组件
class Like extends React.Component{
render(){
return <h1>你喜欢我</h1>
}
}
// 渲染组件
ReactDOM.render(<Like /> , document.getElementById("test"))
第二步:初始化state
你喜欢我 会变成 我喜欢你 点击切换变化
使用类构造器,定义一个标识 isLike (存放在状态state里)false 你喜欢我 true 我喜欢你
//创建组件
class Like extends React.Component{
constructor(props){
//调用父类的构造函数
super(props)
// 初始化状态
this.state = {
isLike:false
}
}
// 在render中state中存储的数据
render(){
// 读取状态
const {isLike} = this.state
return <h1>{isLike ? '我喜欢你' : '你喜欢我' }</h1>
}
}
// 渲染组件
ReactDOM.render(<Like /> , document.getElementById("test"))
第三步:React中的事件绑定
// 创建组件
class Like extends React.Component{
constructor(props){
super(props)
// 初始化状态
this.state = {
isLike:false
}
}
// 在render中state中存储的数据
render(){
// 读取状态
const {isLike} = this.state
return <h1 onClick={changeLike}>{isLike ? '我喜欢你' : '你喜欢我' }</h1>
}
}
// 渲染组件
ReactDOM.render(<Like /> , document.getElementById("test"))
function changeLike(){
console.log("触发了点击事件");
}
-
React 事件绑定属性的命名采用驼峰式写法,而不是小写。比如: onClick
-
如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)
-
HTML 通常写法是:
<button onclick="activateLasers()">激活按钮</button>
-
React 中写法为:
<button onClick={activateLasers}>激活按钮</button>
第四步 在点击事件中修改isLike的值
问题一、:第三步的function的this指向undefined 获取不到isLike(不采用这种写法 将事件写入类里面)
- 将事件写入类里面,changeLike this指向undefined
class Like extends React.Component{
constructor(props){
super(props)
this.state = {
isLike:false
}
console.log(this); // 类实例对象
}
render(){
console.log(this); // 类实例对象
// 读取状态
const {isLike} = this.state
return <h1 onClick={this.changeLike}>{isLike ? '我喜欢你' : '你喜欢我' }</h1>
}
changeLike(){
console.log(this); // this 是 undefined
console.log("触发了点击事件");
console.log(this.state.isLike);
}
}
// 渲染组件
ReactDOM.render(<Like /> , document.getElementById("test"))
constructor、render、changeLike的this指向
注意:
-
changeLike ==》放在了Like的原型上,供实例使用
-
通过Like实例调用changeLike时,changeLike中的this就是Like实例
-
<h1 onClick={this.changeLike}>{isLike ? '我喜欢你' : '你喜欢我' }</h1>
并不是通过Like实例调用的 -
由于changeLike是作为onClick的回调,所以不是通过实例调用的,是直接调用
-
类中的方法默认开启了局部的严格模式,所以changeLike中的this为undefined
解决办法
this.changeLike = this.changeLike.bind(this);
class Like extends React.Component{
constructor(props){
super(props)
// 初始化状态
this.state = {
isLike:false
}
// 生成了新的函数 改变函数的this指向
// 在实例自身上生成一个方法
// 解决changeLike中this指向问题
this.changeLike = this.changeLike.bind(this);
}
render(){
console.log(this);
const {isLike} = this.state
return <h1 onClick={this.changeLike}>{isLike ? '我喜欢你' : '你喜欢我' }</h1>
}
changeLike(){
console.log(this);
console.log("触发了点击事件");
console.log(this.state.isLike);
}
}
// 渲染组件
ReactDOM.render(<Like /> , document.getElementById("test"))
- 修改isLike的值(setState),完成需求
class Like extends React.Component{
constructor(props){
super(props)
this.state = {
isLike:false
}
this.changeLike = this.changeLike.bind(this);
}
render(){
const {isLike} = this.state
return <h1 onClick={this.changeLike}>{isLike ? '我喜欢你' : '你喜欢我' }</h1>
}
changeLike(){
// 获取isLike的值 直接修改
const isLike = this.state.isLike;
//注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
this.setState({isLike:!isLike})
//注意:状态(state)不可直接更改,下面这行就是直接更改!!!
//this.state.isLike = !isLike //这是错误的写法
}
}
// 渲染组件
ReactDOM.render(<Like /> , document.getElementById("test"))
实例说明:
-
setState每次修改内容会自动触发React重新渲染页面
-
因此示例中每次点击都会修改状态,更加状态重新渲染内容,达到内容切换的目的
-
constructor ———— 调用了1次
-
render ———— 调用1+n次 1是初始化的那次 n是状态更新的次数
-
changeLike ———— 点几次调几次
State状态理解
-
state 是组件对象中最重要的属性,值是对象(可以包含多个数据)
-
组件被称为"状态机",通过更新组件的state来更新对应的页面显示(重新渲染组件)
-
state是组件实例的属性,函数组件没有实例,因为函数组件没有状态
-
state可以理解是组件自己的数据, props数据是外部传入,state数据就是组件自己的
State的使用规则
-
state 通常在组件的constructor中进行初始化
-
state 只能用setState方法更新
-
setState会导致render重新执行,渲染组件和所有的子组件
1)初始化状态
constructor(props){
super(props)
this.state = {
stateProp1 : value1,
stateProp2 : value2
}
}
2)读取某个状态
this.state.statePropertyName
this.state.stateProp1
3)更新状态 —> 组件界面更新
this.setState({
stateProp1 : value1,
stateProp2 : value2
})
状态的简写定义
说明
-
ES6 class类中 constructor 函数为构造函数, 内部通过this定义的属性是类实例的属性
-
class类中其他的方法确实实例原型上的方法
-
但是class类中的表达式定义的内容确实实例上的内容
示例
class Person {
constructor() {
// 实例属性
this.name = "张三"
}
// 实例上的属性
age = 18
// 实例上的方法
eat = function () {
console.log("eat")
}
// 原型上的方法
run() {
console.log("eat")
}
}
var p1 = new Person
console.log(p1)
打印结果如下:
实例说明
-
ES6中class类里定义的表达式,无论是函数表达式,函数普通的表达式,最后都是实例的属性或方法
-
ES6中class类中普通定义的函数是实例原型上的方法
对state-demo进行简写
// 创建组件
class Like extends React.Component {
//初始化定义state状态
state = {
isLike: false
}
render() {
const { isLike } = this.state
return <h1 onClick={this.changeLike}>{isLike ? '我喜欢你' : '你喜欢我'}</h1>
}
//组件实例化上的方法
changeLike = () => {
const isLike = this.state.isLike;
this.setState({ isLike: !isLike })
}
}
// 渲染组件
ReactDOM.render(<Like />, document.getElementById("test"))
强烈注意
组件中render方法中的this为组件实例对象
组件自定义的方法中this为undefined,如何解决?
-
强制绑定this: 通过函数对象的bind()
-
箭头函数
状态数据,不能直接修改或更新
React中更新State对象的某一个属性值
数据如下
this.state = {
login: {
username: '',
password: ''
}
}
修改username
正确更新
const login = this.state.login
login.username = 'admin'
this.setState({ login })
- 得到login的地址,再对对象属性赋值,更新对象