React的类组件和函数组件

95 阅读3分钟

0.两种组件的写法

类组件

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

使用方法:<Welcome name="XXX">

函数组件

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

使用方法:<Welcome name="XXX">

相同与不同

  • 标签都会被翻译成React.CreateElement,根据传入值的类型不同来返回不同的结果。
    1. 传入字符串,创建对应标签
    2. 传入函数,调用传入函数并获取其返回值
    3. 传入类,调用类的构造函数,获取一个组件对象,然后调用该对象的render函数,获取返回值

属性传递Props

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

函数组件直接读取函数的参数props.XXX

数据状态State

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

函数组件使用[n, setN] = React.useState(初始状态)

注意点

React修改数据不会即时地更新UI,需要调用setState异步地更新UI。

不推荐在原有的对象上进行修改,一般参考setState({n:state.n+1})这种写法

复杂State的操作

类组件

React会自动合并第一层的属性,不需要额外操作

class Son extends React.Component {
  constructor() {
    super();
    this.state = {
      n: 0,
      m: 0
    };
  }
  addN() {
    this.setState({ n: this.state.n + 1 });
  }
  addM() {
    this.setState({ m: this.state.m + 1 });
  }
  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>
    );
  }
}

但是不会合并第二层的对象,可以使用展开运算符将属性赋值到新对象上,然后改变数据

// Ojbect.assign会新建空对象,把之前的数据复制到空对象里
 changeUser() {
    const user = Object.assign({}, this.state.user);
    user.name = "jack";
    this.setState({
      user: user
    });
  }
  
//...
changeUser() {
    this.setState({
      // m 和 n 不会被置空
      user: {
        ...this.state.user, // 复制之前的所有属性
        name: "jack"
        // age 被置空
      }
    });

函数组件

不会自动合并

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>
  );
};
const Grandson = () => {
  const [state, setState] = React.useState({
    n: 0,
    m: 0
  });
  return (
    <div className="Grandson">
      孙子 n:{state.n}
     <button onClick={() => setState({...state, n: state.n + 1 })}>n+1</button>
      m:{state.m}
     <button onClick={() => setState({...state, m:state.m + 1})</button>>
    </div>
  );
};

事件绑定

类组件的标准写法

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

在声明时使用箭头函数并命名

典型错误

class Son extends React.Component{
   addN(){ 
      this.setState({n: this.state.n + 1})
    }

    addN: function(){
      this.setState({n: this.state.n + 1})
    }
} 

  • 正确写法的addN函数是对象本身的属性,意味着每个Son组件都可有自己的addN函数,例如,两个Son,每个都会有自己的addN函数。因为this指向Son组件

  • 错误的addN函数是对象的共有属性,也就是原型上的属性,即prototype里面。意味着所有的Son组件共用一个addN函数。因为this指向全局变量window

区别

  • props 是传递给组件的(类似于函数的形参),而 state 是在组件内被组件自己管理的(类似于在一个函数内声明的变量)

  • props 是组件的只读属性,组件内部不能直接修改 props ,要想修改 props ,只能在该组件的上层组件中修改

  • state 是在组件中创建的,一般在 constructor 中初始化 state

  • state是可变的,是组件内部维护的一组用于反映组件UI变化的状态集合

  • state 是多变的、可以修改,每次 setState异步更新