React组件

90 阅读3分钟

类组件和函数组件

vue中一个构造选项就表示一个组件;React中一个返回的React元素的函数就是组件

React元素(d小写):const div = React.createElement('div',...)

React组件(D大写):const Div = ()=> React.createElement('div',...)

1. 函数组件

function Welcome(props){
    return <h1>hello, {props.name}</h1>
}

使用方法:<Welcome name="frank" />

2. 类组件

class Welcome extends React.Component{
    constructor(){
        super();
        this.state = {}
    }
    render(){
        return <h1>hello, {this.props.name}</h1>
    }
}

使用方法:<Welcome name="frank" />

Babel 翻译xml为js的原则

<div />会被翻译为React.craeteElement('div')
<Welcome />会被翻译为React.createElement(Welcome)

uTools_1687589445104.png

React.createElememt的逻辑

如果传入一个字符串'div',则会创一个div(虚拟DOM)
如果传入一个函数,则会调用该函数,获取其返回值
如果传入一个类,则在类前面加个new(导致执行constructor),获取一个组件对象,然后调用对象的render方法,获取其返回值

props和state

react的props相当于vue的props;react的state相当于vue的data

  • 添加props(外部数据):

示例

类组件直接读取属性this.props.xxx

函数组件世界读取参数props.xxx

  • 添加state(内部数据):

示例

类组件用this.state读,this.setState

addN = () => {
    this.setState({ n: this.state.n + 1 });
};

<button onClick={this.addN}>n+1</button>

函数组件用useState返回数组,第一项读,第二项写【 x读,y写名字随便】

const [n, setN] = React.useState(0);
<button onClick={() => setN(n + 1)}>+1</button>

setState是异步函数,它会异步改变n,react推荐你创建一个新对象【详情见下‘类组件注意项’】

setN永远不会改变n,他会创建一个新的n

小试牛刀

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  return (
    <div className="App">
      爸爸
      <Son />
    </div>
  );
}

class Son extends React.Component {
  constructor() {
    super();
    this.state = {
      n: 0
    };
  }
  add() {
    // this.state.n += 1 为什么不行
    this.setState({ n: this.state.n + 1 });
  }
  render() {
    return (
      <div className="Son">
        儿子 n: {this.state.n}
        <button onClick={() => this.add()}>+1</button>
        <Grandson />
      </div>
    );
  }
}

const Grandson = () => {
  const [n, setN] = React.useState(0);
  return (
    <div className="Grandson">
      孙子 n:{n}
      <button onClick={() => setN(n + 1)}>+1</button>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

类组件注意事项:

为啥add写this.state .n+=1页面无变化? 因为他不像vue一样对数据进行监听劫持并渲染在视图上【其实n已经变了,但UI不会自动更新视图】。react调用setState修改数据才会触发UI更新。

不要像下面这样直接改

uTools_1687595601514.png

我们推荐创建新的对象(数据不可变),但不推荐用这种方法

uTools_1687595685972.png

我们推荐setState(函数)这样的写法

uTools_1687596144098.png(简单情况这样写)

uTools_1687596507259.png(复杂情况这样写)

因为setState是异步函数。你把n打印出来就会发现点击+1后先打印0再执行+1操作

uTools_1687596245147.png

函数组件注意事项:

与类组件相同的地方:通过setX(新值)来更新UI

与类组件不同的地方:没有this,一律用参数和变量

复杂State

类组件的setState只会自动合并第一层属性(修改值时只会正常复制第一层所有属性再set要改变的属性)更深层的在则需要用Object.assign // 浅拷贝,不要用或者...操作符

函数组件setX完全不会合并,需要自己手动合并

例子:

类组件里有n和m

class Son extends React.Component {
    constructor() {
      super();
      this.state = {
        n: 0,
        m: 0
      };
    }
    addN() {
      this.setState({ n: this.state.n + 1 });
      // m 会被覆盖为 undefined 吗?不会
    }
    addM() {
      this.setState({ m: this.state.m + 1 });
      // n 会被覆盖为 undefined 吗?不会
    }
    render() {
      return (
        <div className="Son">
          儿子 n: {this.state.n}
          <button onClick={() => this.addN()}>n+1</button>
          m: {this.state.m}
          <button onClick={() => this.addM()}>m+1</button>
          <Grandson />
        </div>
      );
    }
  }
  
  const Grandson = () => {
    const [n, setN] = React.useState(0);
    return (
      <div className="Grandson">
        孙子 n:{n}
        <button onClick={() => setN(n + 1)}>+1</button>
      </div>
    );
  };

不会合并第二层属性例子:

uTools_1688138447495.png

  1. Object.assign解决【浅拷贝,不要用】

uTools_1688137955453.png

  1. ...操作符

uTools_1688138316794.png

函数组件里有n和m:

uTools_1688118612244.png

不推荐对象这种写法,因为不写...state,m就会被置空:

uTools_1688136506487.png

绑定事件

类组件最推荐的写法:

class Son extends React.Component{
    addN= ()=>this.setState({ n: this.state.n + 1 })
    render(){
        return <button onClick={this.addN}>+1</button>
    }
}

其他写法:

uTools_1688140045974.png

函数组件写法:

const [n, setN] = React.useState(0); <button onClick={() => setN(n + 1)}>+1</button>

this + 面试题

react理念:

  1. 数据不可变 --> setState创建一个新的state而不改变原来的state
  2. diff算法找虚拟DOM间的不同并局部更新DOM

两种编程模型: 微信截图_20230629185755.png