03 React 面向组件编程


可以在谷歌应用商店下载 React Developer Tools,可以更好用

React 中定义函数式组件

<script type="text/babel">
    //1.编写函数式组件
    function Demo() {//组件名需要大写,不然 react 会认为标签里面是 html 标签,而不是 react 组件
        console.log(this);  //此处的 this 是 undefined,因为babel 会在严格模式下翻译代码,严格模式下,函数里的 this 为 undefined
        return (
            <h1>函数式组件</h1>
        )
    }
    //2.渲染组件到页面
    ReactDOM.render(<Demo/>, document.getElementById('test'));
script>

执行ReactDOM.render()之后,发生了什么?

  1. React 解析组件标签,找到了 Demo 组件
  2. 发现 Demo 组件是用函数定义的,随后调用该函数,将返回的虚拟 DOM 转为真实 DOM,然后呈现到页面中。

React 中定义类组件

类的基本知识

<script type="text/javascript">

    /*
    1.类中的构造器不是必须要写的,要对实例进行属性初始化的时候就要写
    2.如果 A 类继承了 B 类,且 A 类写了构造器,那么构造器需要在首行调用super()
    3.类中所定义的方法,都是放在了类的原型对象上,供实例去使用。
     */

    //创建一个类
    class Person {
        //构造器方法
        constructor(name, age) {
        //构造器中的 this 是谁?类的示例对象
        this.name = name
        this.age = age
     }
     //一般方法
     speak() {
         //speak方法放在了哪里?类的原型对象上,供实例使用
         //通过 person 实例调用 speak 方法,speak 方法中的 this 指向了 person 实例
         console.log(`我叫${this.name},今年${this.age}岁了。`)
        }
     }

     const p1 = new Person('Tom', 18)
     const p2 = new Person('Jerry', 19)

     p1.speak()
     p2.speak()

     class Student extends Person {
        constructor(name, age, grade) {
            super();  //必须要调用,否则会报错。调用的好处时,父类拥有的属性赋值就不用写了
            // this.name = name; 
            // this.age = age;
            this.grade = grade;
        }
        //重写父类方法
        speak() {
            console.log(`我叫${this.name},今年${this.age}岁了,在读${this.grade}`)
        }
    }

    const s1 = new Student('xiaozhang', 12, '高一');
    const s2 = new Student('xiaomei', 13, '高二');

    s1.speak()
    s2.speak()
script>

创建类式组件

DOCTYPE html>
<html>
<head>
    <title>React创建类组件title>
head>
<body>
    <div id="test">div>
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin>script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin>script>
    
    <script src="https://unpkg.com/@babel/standalone/babel.min.js" crossorigin>script>
    <script type="text/babel">
        //1.创建类式组件
        class MyComponent extends React.Component{
            render() {
                return <h1>React创建类式组件</h1>
            }
        }
        ReactDOM.render(<MyComponent/>, document.getElementById('test'))
    script>
body>
html>

组件的 render 是放在哪里的?

  • 组件的 render 放在类的原型对象上,供实例对象使用。

那组件的实例呢?

执行了 ReactDOM.render()之后,发生了什么?

  1. ReactDOM 解析组件标签,找到了 MyComponent 组件
  2. 发现组件是使用类定义的,随后 new 出来该类的实例,并通过该实例调用原型上的 render 方法
  3. 将 render 返回的虚拟 DOM 转为真实 DOM,随后呈现在页面上。

组件实例的三大属性之state

以下代码借助 state 状态,在按钮每次点击之后,都会改变h1标签的内容

<script type="text/babel">
    class MyComponent extends React.Component{
    	//组件被调用几次,构造器就调用几次
        constructor(props) {
            super(props);
            this.state={isHot:false};
            this.handleClick = this.handleClick.bind(this);
        }

        handleClick() {
        	//setState 的操作是一种合并操作,而不是更新。但是 hooks 的操作好像是合并的
            this.setState({isHot:!this.state.isHot});
        }
		//render被调用了 1+n 次,1 是初始化那次,n 是状态更新的次数
        render () {
            return <h1 onClick={this.handleClick}>今天的天气很{this.state.isHot?"炎热":"寒冷"}</h1>
        }
    }

    ReactDOM.render(<MyComponent/>, document.getElementById('test'));
script>

类中的方法默认开启了严格模式,this 是 undefined
this.handleClick = this.handleClick.bind(this)这行代码是必要的,因为它确保了在组件的方法中使用this关键字时,this关键字指向组件实例。
在 Javascript 中,函数的this关键字指向的是当前执行上下文的对象。在 React 组件中,我们经常需要在组件的方法中使用this关键字来访问组件的状态或者其他属性和方法。但是,在不进行绑定的情况下,这些方法中的this关键字指向的是调用该方法的对象,这可能导致代码中的错误或者不可预料的行为。

​state 的简写方式

class MyComponent extends React.Component{
    //初始化状态
    //这样相当于给类增加了一个属性
    state = {isHot:true};

    //如果这里写成函数表达式,那么 this 将找不到而导致出错
    handleClick = () => {
        this.setState({isHot:!this.state.isHot});
    }

    render () {
        return <h1 onClick={this.handleClick}>今天的天气很{this.state.isHot?"炎热":"寒冷"}</h1>
    }
}

ReactDOM.render(<MyComponent/>, document.getElementById('test'));

强烈注意:

  • 组件中 render 方法中的 this 为组件实例对象
  • 组件自定义的方法中 this 为 undefined,如何解决?
    - 强制绑定 this,通过函数对象的 bind()
    - 箭头函数
  • 状态数据,不能直接修改或更新 setState

组件的三大属性之props

<script type="text/babel">
    class Person extends React.Component {
        render() {
            return (
                <ul>
                    <li>姓名:{this.props.name}</li>
                    <li>性别:{this.props.gender}</li>
                    <li>年龄:{this.props.age}</li>
                </ul>
            )
        }
    }

    //在组件标签中传值,相当于就是往组件的 props 中传值了
    ReactDOM.render(<Person name="Tom" gender="男" age="18"/>, document.getElementB-yId('test'));
script>

在组件标签中传值,相当于就是往组件的 props 中传值了

用这样的写法,可以将一个对象的键值对都放在组件的 props 中:
(展开运算符本来不能展开对象的,但是加了花括号后可以用来对象克隆)
(但是在这里,花括号的含义是里面要写 javascript 代码了,只是说 babel+react 语法允许我们使用展开运算符来展开对象,在正常的 javascript 代码中,展开运算符是不能展开对象的,只能与花括号配合来克隆对象)

const p = {name:"小陈", age:18, gender:"男"}
ReactDOM.render(<Person {...p}/>, document.getElementById('test'));

注意,虽然react+babel可以使用展开运算符展开对象,但是也不能随意使用,比如下面这样就不太行。

const p = {name:"小陈", age:18, gender:"男"}
console.log(...p);   //这样不行

复制对象时,修改对象属性的时候也可以用

const p = {name:"小陈", age:18, gender:"男"}
const p1 = {...p, name:'小张'}

你可能感兴趣的:(React全家桶,react.js,javascript,前端)