React三大核心属性State、Props和Refs的详细介绍以及React组件的详细介绍

一、 基本理解和使用

1. 使用React开发者工具调试

下载链接:React开发者工具

2. React组件的两种形式

  • 函数式组件:

    // 1.创建函数式组件
    function MyComponent() {
      console.log(this); // 此处的this是undefined,因为babel编译后开启了严格模式禁止普通函数的this指向window
      return <h2>函数式定义的组件(适用于【简单组件的定义】)</h2>;
    }
    // 2.渲染组件到页面
    ReactDOM.render(<MyComponent />, document.getElementById("test"));
    /**
     * 执行了ReactDOM.render(<MyComponent />,...)之后,发生了什么?
     *      1.React解析组件标签,找到了Mycomponent组件
     *      2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转化为真实DOM,随后呈现在页面中。
     */
    
  • 类式组件:

    // 1.创建类式组件
    class MyComponent extends React.Component {
      render() {
        // render是放在哪?——MyComponent类的原型对象上,供实例使用
        // render中的this是 MyComponent组件实例对象。
        return <h2>类定义的组件(适用于【复杂组件】)</h2>;
      }
    }
    // 2.渲染组件到页面
    ReactDOM.render(<MyComponent />, document.getElementById("test"));
    /**
     * 执行了ReactDOM.render(<MyComponent />,...)之后,发生了什么?
     *      1.React解析组件标签,找到了Mycomponent组件
     *      2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用原型上的render方法
     *      3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面上
     */
    

3. 注意

  • 组件名必须首字母大写

  • 虚拟DOM元素只能有一个根元素

  • 虚拟DOM元素必须有结束标签

4. 渲染类组件标签的基本流程

  • React内部会创建组件实例对象

  • 调用render()得到虚拟DOM, 并解析为真实DOM

  • 插入到指定的页面元素内部

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

1. 效果

需求:定义一个展示天气信息的组件

  • 默认展示天气炎热 凉爽

  • 点击文字切换天气

2. 理解

  • state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)

  • 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

  • 代码如下

    // 1.创建类式组件
    class Weather extends React.Component {
      // 构造器调用几次?—— 1 次
      constructor(props) {
        super(props);
        // 初始化状态
        this.state = {
          isHot: true,
          wind: "微风",
        };
        // 解决changeWeather中的this指向问题
        this.changeWeather = this.changeWeather.bind(this);
      }
    
      // render调用几次?—— 1+n 次  :1是初始化那次  n是setState的调用的次数(即状态更新的次数)
      render() {
        // 读取状态
        return (
          <h1 onClick={this.changeWeather}>
            今天天气很{this.state.isHot ? "炎热" : "凉爽"}{this.state.wind}
          </h1>
        );
      }
    
      // changeWeather调用几次?—— 点几次调用几次
      changeWeather() {
        // changeWeather方法放在了哪?——Weather原型对象上,供实例使用
        // 通过Weather实例调用changeWeather时,changeWeather中的this就是Weather实例对象
        // 由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用的
        // 类中的方法默认开启了严格模式,所以changeWeather中的this为undefined
    
        // 严重注意:状态(state)不可以直接更改,下面这行就是直接更改!!!
        // this.state.isHot = !this.state.isHot  //react不认可
    
        // 严重注意:状态(state)必须通过setState进行更改,且更新是合并
        this.setState({
          isHot: !this.state.isHot,
        });
        // console.log(this);
      }
    }
    // 2.渲染组件到页面
    ReactDOM.render(<Weather />, document.getElementById("test"));
    
  • 简写方式

    // 1.创建类式组件
    class Weather extends React.Component {
      // 初始化状态
      state = {
        isHot: true,
        wind: "微风",
      };
    
      render() {
        return (
          <h1 onClick={this.changeWeather}>
            今天天气很{this.state.isHot ? "炎热" : "凉爽"}{this.state.wind}
          </h1>
        );
      }
    
      // 自定义方法 —— 要用赋值语句 + 箭头函数
      // 其实就是给实例对象身上添加changeWeather方法
      // 箭头函数为了能够使这个函数访问到的this是该实例对象
      changeWeather = () => {
        this.setState({
          isHot: !this.state.isHot,
        });
        // console.log(this);
      };
    }
    // 2.渲染组件到页面
    ReactDOM.render(<Weather />, document.getElementById("test"));
    
    

3. 强烈注意

  • 组件中render方法中的this为组件实例对象

  • 组件自定义的方法中this为undefined,如何解决?

    • 强制绑定this: 通过函数对象的bind()
    • 箭头函数(赋值语句形式)
  • 状态数据,不能直接修改或更新,需使用serState方法

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

1. props的含义

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

2. props作用

  • 通过标签属性从组件外向组件内传递变化的数据
  • 注意: 组件内部不要修改props数据,因为它是只读的

3. 使用方式

  • 传递的方式

    <!-- 方式一 -->
    <Person name="tom" gender="" age={23} />
    <!-- 方式二:将对象的所有属性通过props传递(扩展属性)
    	 person = {name:'xzq',age:20}
    -->
    <Person {...person}/>
    
  • props的读取

    this.props.name
    

4. 对props中的属性值进行类型限制和必要性限制

  • 第一种方式(React v15.5 开始已弃用):

    Person.propTypes = {
      name: React.PropTypes.string.isRequired,
      age: React.PropTypes.number
    }
    
  • 第二种方式(新):使用prop-types库进限制(需要引入prop-types库)

    Person.propTypes = {
      name: PropTypes.string.isRequired,
      age: PropTypes.number. 
    }
    

5. props的默认值

  • 使用defaultProps

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

6. 组件类的构造函数里的props小细节

若构造器中没有传递props,或传递了props,但是super调用未传递props,则通过this使用props可能会出现this.props为undefined的情况

7. 类式组件的props

  • 对props的属性限制的方式一

    // 1.创建组件
    class Person extends React.Component {
      render() {
        // console.log(this);
        const { name, gender, age } = this.props;
        // props是只读的
        // this.props.name = 'jack' // 报错,因为props是只读的
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{gender}</li>
            <li>年龄:{age + 1}</li>
          </ul>
        );
      }
    }
    // 对标签属性进行类型、必要性的限制
    Person.propTypes = {
      name: PropTypes.string.isRequired, // 限制name必传,且为字符串
      gender: PropTypes.string, // 限制gender为字符串
      age: PropTypes.number, // 限制age为数字
      speak: PropTypes.func, // 限制sprak为函数
    };
    // 指定props属性默认值
    Person.defaultProps = {
      gender: "男", // gender默认值为男
      age: 18, // age默认值为18
    };
    
  • 对props的属性限制的方式二(简写方式)

    // 1.创建组件
    class Person extends React.Component {
      // 对标签属性进行类型、必要性的限制
      // static修饰的属性表示给Person添加属性
      static propTypes = {
        name: PropTypes.string.isRequired, // 限制name必传,且为字符串
        gender: PropTypes.string, // 限制gender为字符串
        age: PropTypes.number, // 限制age为数字
        speak: PropTypes.func, // 限制sprak为函数
      };
    
      // 指定props属性默认值
      static defaultProps = {
        gender: "男", // gender默认值为男
        age: 18, // age默认值为18
      };
    
      render() {
        const { name, gender, age } = this.props;
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{gender}</li>
            <li>年龄:{age + 1}</li>
          </ul>
        );
      }
    }
    

8. 函数组件的props

// 1.创建组件
function Person(props) {
  // console.log(props);
  const { name, sex, age } = props;
  return (
    <ul>
      <li>姓名:{name}</li>
      <li>性别:{sex}</li>
      <li>年龄:{age}</li>
    </ul>
  );
}
// 对标签属性进行类型、必要性的限制
Person.propTypes = {
  name: PropTypes.string.isRequired, // 限制name必传,且为字符串
  sex: PropTypes.string, // 限制gender为字符串
  age: PropTypes.number, // 限制age为数字
};
// 指定props属性默认值
Person.defaultProps = {
  sex: "男", // gender默认值为男
  age: 18, // age默认值为18
};

四、组件三大核心属性3:refs

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

1. 字符串形式的ref

React官方不推荐使用的一种方式,因为存在一些效率上的问题,应避免使用

  • 使用方式:

    • 标识:<input ref="input1"/>

    • 获取:this.refs.input1

  • 代码如下

    class Demo extends React.Component {
      // 展示左侧输入框数据
      showData = () => {
        const { input1 } = this.refs;
        alert(input1.value);
      };
      // 展示右侧输入框数据
      blurHandler = () => {
        const { input2 } = this.refs;
        alert(input2.value);
      };
      render() {
        return (
          <div>
            <input ref="input1" type="text" placeholder="点击按钮提示数据" />
            &nbsp;
            <button onClick={this.showData}>点我提示左侧的数据</button>&nbsp;
            <input
              ref="input2"
              onBlur={this.blurHandler}
              type="text"
              placeholder="失去焦点提示数据"
            />
          </div>
        );
      }
    }
    

2. 回调形式的ref

  • 内联函数方式的回调使用方式

    // 内联函数方式定义回调函数,初始时执行一次,在更新过程(再次执行render时)中会被执行两次,第一次为null表示清空旧的ref,第二次传入的才是DOM元素
    // 参数c表示当前DOM元素
    <input ref={(c)=>{this.input1 = c}}
    
  • 类实例方法形式的回调函数

    class Demo extends React.Component {
      state = { isHot: true };
      showInfo = () => {
        alert(this.input1.value);
      };
      changeWeather = () => {
        this.setState({
          isHot: !this.state.isHot,
        });
      };
      saveInput = (c) => {
        this.input1 = c;
        console.log(c);
      };
      render() {
        return (
          <div>
            <div>今天天气很{this.state.isHot ? "炎热" : "凉爽"}</div>
            <hr />
            {
              // 内联函数方式定义回调函数,初始时执行一次,在更新过程(再次执行render时)中会被执行两次,
              // 第一次为null表示清空旧的ref,第二次传入的才是DOM元素
              /*<input ref={c => { this.input1 = c; console.log(c); }} type="text" placeholder="" />&nbsp;<br /><br />*/
            }
            {
              // 定义成类实例方法形式的回调函数,同样会收到一个参数c表是当前DOM元素,只有在初始时调用一次,后面的更新不会再调用
              // 关于React官网说明:两种方式选择哪种都是无关紧要的
            }
            <input ref={this.saveInput} type="text" />
            &nbsp;
            <br />
            <br />
            <button onClick={this.showInfo}>点我提示输入的数据</button> &nbsp;
            <button onClick={this.changeWeather}>点我切换天气</button>&nbsp;
          </div>
        );
      }
    }
    

3. createRef形式的ref

  • 使用createRef创建ref容器

    • React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点
    • 该容器是"专人专用"的,一一对应,即不能使用同一个容器标识多个DOM元素
    // this.myRef.current为当前的DOM元素
    myRef = React.createRef() 
    <input ref={this.myRef} />
    

4. 事件处理

  • 通过onXxx属性指定事件处理函数(注意大小写与原生不同,原生是onxxx)

    • React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —— 为了更好的兼容性
    • React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)——为了高效
    • 事件绑定一定是本着一个原则:必须把一个函数交给事件
  • 通过event.target得到发生事件的DOM元素对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘎嘎油

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值