React组件分两种:

  • 函数组件
  • 类组件

函数组件

  1. function Weblcome(props) {
  2. return <h1>Hello,{props.name}</h1>
  3. }

使用方法: <Welcome name="frank"> ,而 name="frank" 为外部传入组件的数据。

类组件

  1. class Welcome extends React.Component {
  2. render() {
  3. return <h1>Hello,{this.props.name}</h1>
  4. }
  5. }

使用方法: <Welcome name="frank"> ,而 name="frank" 为外部传入组件的数据。

组件翻译

<Welcome /> 会被翻译成什么?

注意,在React里,写类似这种 <div /> ,这不是HTML!!!

  • <div /> 会被翻译成 React.createElement('div') ,div是个虚拟DOM!
  • <div /> 不同的是,因为 <Welcome /> 是函数组件,会被翻译成 React.createElement(Welcome)

看出来:

  • React.createElmenet() 可以接受字符串和函数。
  • 如果传入一个字符串’div’,则会创建一个div。
  • 如果传入一个函数,则会调用该函数,获取其返回值。
  • 如果传入一个类,则会在类的前面加个 new (这会导致执行才constructor),获取一个组件对象,然后调用对象的render方法,获取其返回值。

还有个翻译器可以翻译:翻译器

props和state

props是外部数据,state是内部数据!

props

  • 类组件会直接读取属性 this.props.xxx
  • 函数组件读取直接读取参数 props.xxx

如下:

类组件的props

React组件 - 图1

函数组件的props

React组件 - 图2

state

  • 类组件使用 this.state 读, this.setState 写, setState异步改变n的值。
  • 函数组件用 useState 返回数组,第一项读,第二项写, useState 不会改变n的值。

如:

类组件

React组件 - 图3

函数组件

React组件 - 图4

setState注意事项
  1. this.state.n += 1 是无效的。

    实际上n已经改变,只不过UI并不会自动更新,需要调用setState才会触发UI更新(异步更新),这和Vue的不同,Vue还可以监听data一样,而React没有。

  2. setState会异步更新UI。

    所以,setState之后,state是不会马上改变的,在还没执行完之后的代码,读取值依旧是旧值,所以需要等待剩下的代码执行完毕后state才会改变。

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

    需要了解React一个思想,React是不推荐更改以前的旧值,而是创建一个新的对像,这和Vue相反!所以不要修改state(不可变数据)。

state复杂情况处理

如果state里有n和m

类组件的写法:
React组件 - 图5

函数组件:
React组件 - 图6

需要注意的是:类组件的setState会自动合并第一层属性,但不会合并第二层属性,而函数组件都不会自动合并属性。解决办法是使用扩展运算符 ... 合并属性。

事件绑定的写法

类组件:

  1. <button onClick={()=> this.addN()}> n+1 </button> //可以这么写
  2. <button onClick={()=> this.addN}> n+1 </button> //不能这么写,这里的this变成window
  3. <button onClick={()=> this.addN.bind(this)}> n+1 </button> //可以但还不如第一条
  4. this._addN = () => this.addN()
  5. <button onClick={()=> this._addN}> n+1 </button> //这个可以,但是需要想一个名字,以下改良

以下是改良后的代码

  1. constructor(){
  2. this.addN = () => this.setState({n: this.state.n + 1})
  3. }
  4. render(){
  5. return <button onClick={this.addN}> n+1 </button>
  6. }

改良后好了很多,但React的团队看了之后干脆出了个语法糖,也就是最终的写法:

  1. class Son extends React.Component{
  2. addN = () => this.setState({n: this.state.n + 1}); //可以写在外面了!效果与上面的改良后代码没区别
  3. render(){
  4. return <button onClick={this.addN}> n+1 </button>
  5. }
  6. }

小试牛刀

  1. import React from "react";
  2. import ReactDOM from "react-dom";
  3. import "./styles.css";
  4. function App(){
  5. return (
  6. <div className="App">
  7. 爸爸
  8. <Son />
  9. </div>
  10. )
  11. }
  12. class Son extends React.Component{
  13. constructor(){
  14. super();
  15. this.state = {
  16. n: 0
  17. }
  18. }
  19. add(){
  20. this.setState({n: this.state.n + 1});
  21. }
  22. render(){
  23. return (
  24. <div className="Son">
  25. 儿子 n:{this.state.n}
  26. <button onClick={() => this.add()}>+1</button>
  27. <Grandson/>
  28. </div>
  29. )
  30. }
  31. }
  32. const Grandson = () => {
  33. const [n, setN] = React.useState(0);
  34. return (
  35. <div className="Grandson">
  36. 孙子 n:{n}
  37. <button onClick={() => setN(n + 1)}> +1 </button>
  38. </div>
  39. )
  40. }
  41. const rootElement = document.getElementById('root');
  42. ReactDOM.render(<App />, rootElement);

image.png