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

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

  1. 显示h1标题, 初始文本为: 你喜欢我
  2. 点击标题更新为: 我喜欢你

第一步:创建一个自定义组件,显示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(不采用这种写法 将事件写入类里面)

  1. 将事件写入类里面,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")) 

  1. 修改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的地址,再对对象属性赋值,更新对象
posted @ 2021-03-04 15:37  流年瓦解我们的记忆  阅读(162)  评论(0编辑  收藏  举报