React类组件和函数组件

1 元素与组件

const div = React.createElement('div',...)
复制代码

这是一个React元素 (d小写)

const Div = () => React.createElement('div'...)
复制代码

这是一个React组件(D大写)

什么是组件?

目前而言,一个返回React元素的函数就是组件

2 React 两种组件

  • 函数组件

    function Welcome(props){
      return <h1> hello, {props.name} </h1>;
    }
    使用方法:
    <Welcome name = "frank"/>
    复制代码
  • 类组件

class Welcome extends React.Component{
  render(){
    return <h1> Hello,{this.props.name}</h1>
  }
}
使用方法:
<Welcome name = "frank"/>
复制代码

3 <Welcome/>

  • 会被翻译成什么

    • <div />会被翻译成React.createElement('div')
    • <Welcome />会被翻译成React.createElement(Welcome)
  • React.createElement的逻辑

    • 如果传入一个字符串‘div’,则会创建一个div(虚拟dom)

    • 如果传入一个函数,则会调用该函数,获取其返回值

    • 如果传入一个,则在类前面价格new(这回导致执行constructor),获取一个组件对象,然后调用对象的render方法,获取其返回值

    class Welcome extends React.Component{
      constructor(){
        super()
        this.state = {n : 0} // 初始化
      }
      render(){
        return <h1> Hello,{this.props.name}</h1>
      }
    }
    new Welcome()
    <Welcome name = "frank"/>
    复制代码

4 添加props(外部数据)

props不能写,只能读!

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

import "./styles.css";

function App() {
  return (
    <div className="App">
      爸爸
      <Son />
      {/* 函数里的子标签可以用class */}
    </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 array = React.useState(0);
  // const n = array[0]
  // const setN = array[1] 得到一个新的n,而不是改变原有的n
  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);
// App 是个函数,调用App(), 创建一个div放到root里
复制代码
<Son messageForSon = "儿子你好" />
<Son messageForSon = {a} /> // 变量
<Son messageForSon = "{hi}" /> // 字符串
复制代码
  • 类组件直接读取属性 this.props.xxx
[{this.props.messageForSon}]
复制代码
  • 函数组件直接读取参数 props.xxx
[{props.messageForGrandson}]
复制代码

5 添加state(内部数据)

(vue里的data)

  • 在类组件中使用state

    用this.state读,用this.setState写

class Son extends React.Component {
  
  constructor() {
    super();
    this.state = {
      n: 0
    };
  }
  // 初始化数据
  
  add() {
    // react不会实时监听,所以this.state.n += 1 不行
    // 写法1 产生一个新的对象(异步)
    this.setState({ n: this.state.n + 1 });
    // 写法2 传入一个旧的state(异步)
    this.setState((state) => {
      return {n : state.n + 1}
    })
    // 写法3
    this.setState((state) => {
      const n = state.n + 1
      return {n}
    })
  }
  
  render() {
    return (
      <div className="Son">
        儿子 n: {this.state.n}
        {/* 读 state的值 this.state.n */}
        <button onClick={() => this.add()}>+1</button>
        {/* 写 state的值 通过this.add()调用this.setState */}
        <Grandson />
      </div>
    );
  }
}
复制代码

注意事项:

  1. this. state.n+=1无效?
    其实n已经改変了,只不过UI不会自动更新而已

    调用 setstateオ会触发UI更新(异步更新)

    因为 React没有像Vue监听data一样监听

  2. setstate会异步更新Ui

    setState之后, state不会马上改变,立马读state会失败 更推荐的方式是 setstate(函数)

  3. this. setstate(this. state)不推荐

    React希望我们不要修改旧 state(不可变数据) 常用代码: setstate((n: state.n+1)

  • 在函数组件中使用state

    用useState给一个初始值返回数组,第一项读,第二项写

const Grandson = () => {
  // 初始值 const [读接口, 写接口]
  const [n, setN] = React.useState(0);
  return (
    <div className="Grandson">
      {/* 读 state的值 {n} */}
      孙子 n:{n}
      {/* 写 state的值 setN   setN不会改变n,而是异步的产生一个新的n*/}
      <button onClick={() => setN(n + 1)}>+1</button>
    </div>
  );
};
复制代码

注意事项:

  1. 跟类组件类似的地方

    也要通过setX(新值)来更新UI

  2. 跟类组件不同的地方

    没有this,一律用参数和变量

6 复杂的state怎么处理

  • 类组件里有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 吗?
        // class组件中的setState如果只对其其中一部分进行修改,其他部分会自动沿用上一次的值
      }
      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>
        );
      }
    }
    复制代码

    类组件的setState会自动合并第一层属性,但是不会合并第二层属性,有两层属性怎么办?

    ...操作符或者Object.assign

    class Son extends React.Component {
      constructor() {
        super();
        this.state = {
          n: 0,
          m: 0,
          user: {
            name: "frank",
            age: 18
          }
        };
      }
    changeUser() {
        this.setState({
          // m 和 n 不会被置空
          user: {
            ...this.state.user,
            // const user = Object.assign({},this.state.user);
            // 等价于 const user = {...this.state.user}
            name: "jack"
            // age 被置空
          }
          // 如果不用... 则 {name:'frank',age:18} => {name:'jack'}
        });
      }
      render() {
        return (
          <div className="Son">
            <button onClick={() => this.changeUser()}>change user</button>
          </div>
        );
      }
    }
    复制代码
  • 函数组件里有n和m

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

    函数组件一般不写setState,因为多个属性不会自动合并

7 事件绑定

  • 类组件的事件绑定

    • 最好这么写
    <button onClick = {() => this.addN()}> n+1 </button>
    复制代码

    ​ 传一个函数给onClick即可

    可改写成

    this._addN = () => this.addN()
    <button onClick = {this._addN}> n+1 </button>
    复制代码

    最终写法

    class Son extends React.Component{
      addN = () => this.setState({n: this.state.n + 1});
    	render(){
        return <button onClick={this.addN}>n+1</button>
      }
    }
    复制代码
    • 不能这么写
    <button onClick = {this.addN}> n+1 </button>
    // button.onClick.call(null, event)
    // this === null =>window
    复制代码

    这样会使得 this.addN 里的 this 变成 window

    • 还有一种写法
    <button onClick = {this.addN.bind(this)}> n+1 </button>
    复制代码

    它返回了一个绑定了当前this新函数

  • 函数组件的事件绑定

function App() {
  const [n, setN] = React.useState(0)
  return ( 
    <div className="App">
      n: {n} 
      <button onClick={()=>setN(n+1)}>+1</button>
    </div>
  );
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享