如何创建Class组件

ES5方式(已过时)

  1. import React from 'react';
  2. const A = React.createClass({
  3. render(){
  4. return (
  5. <div>hi</div>
  6. )
  7. }
  8. })
  9. export default A

因为ES5不支持class,才会有这种方式。

ES6方式

  1. import React from 'react';
  2. class B extends React.Component {
  3. constructor(props){
  4. super(props);
  5. }
  6. render(){
  7. return (
  8. <div>hi</div>
  9. )
  10. }
  11. }
  12. export default B;

以后创建类只用ES6方式,现在还有很多代码是用ES5,即还在搞IE8,如果需要维护就用webpack + babel 将ES6翻译成ES5即可。

Props

即外部数据

作用

  • 接受外部数据,且只能读不能写,外部数据由父组件传递。
  • 接受外部函数,在恰当的时机,调用该函数,该函数一般是父组件的函数。

事例

Parent父组件:

  1. class Parent extends React.Component {
  2. constructor(props){
  3. super(props)
  4. this.state = {name:'frank} //声明外部数据
  5. }
  6. onClick = () => {}
  7. render(){
  8. return <B name={this.state.name} //把外部数据传入到子组件B
  9. onClick={this.onClick}>hi</B> //注意,这个this.onClick传给B组件的是一个地址
  10. }
  11. }

上面的代码里的第八行,外部数据( <B name={this.state.name onClick={this.onClick}>hi</B>} ),被包装成一个对象,如果打印到控制台可以看到 {name:'frank',onClick:...,children:'hi'} ,注意,此处的onClick是一个回调。

B在组件:

  1. class B extends React.Component {
  2. constructor(props){
  3. super(props);
  4. }
  5. render(){}
  6. }

上面的第1行至第3行是固定代码,其中第2行代码与第3行代码是固定搭配,如果不需要引用外部数据可以不写,但是一旦写了就要补全代码不能漏。

根据上面父组件里“传给B组件的是一个地址”的代码注释提示可知, this.props 是一个外部数据的地址。

如何读取外部数据

通过 this.props.xxx 读取如:

  1. class B extends React.Component {
  2. constructor(props){
  3. super(props);
  4. }
  5. render(){
  6. return <div onClick={this.props.onClick}>
  7. {this.props.name}
  8. <div>
  9. {this.props.children}
  10. </div>
  11. </div>
  12. }
  13. }

如何写外部数据

:::danger 禁止写外部数据 :::

理由:这涉及到了React的哲学思想,原则上是应该由数据的主人对数据进行更改!

根据传过来的地址,改外部数据也只会改那个旧的对象的值,并不是新的对象的值,以下代码不推荐:

  1. this.props = {/*另一个对象*/} //改props的值(一个地址)
  2. this.props.xxx = 'hi' //改props的属性

既然是外部数据,就不应该从内部改值。

Props的相关钩子

:::tips 钩子是什么?
可以在生命周期执行的函数 :::

componentWillReceiveProps钩子(已被弃用)
作用:当组件接受新的props时,会触发此钩子。
现在已经被弃用,并更改为 UNSAFE_componentWillReceiveProps 总而言之,这个钩子就不用了,只会在维护旧代码才会看到。

State 与 setState

即内部数据

如何初始化State

如下:

  1. class B extends React.Component {
  2. constructor(props){
  3. super(props);
  4. this.state = {
  5. user: {name: 'frank', age:19}
  6. }
  7. }
  8. render(){ /*...*/}
  9. }

读写内部数据

  • 读:用 this.state ,如: this.state.xxx.yyy.zzz
  • 写:用 this.setState(???,fn) ,如 this.setState(newState,fn)

如:

  1. class App extends React.PureComponent {
  2. constructor(props) {
  3. super(props);
  4. this.state = {
  5. n: 1
  6. }
  7. }
  8. onClick = () => {
  9. this.setState(state => ({n: this.state.n + 1})) //写
  10. }
  11. render(){
  12. return (
  13. <div>
  14. {this.state.n} //读
  15. <button onClick={this.onClick}> +1 </button>
  16. </div>
  17. )
  18. }
  19. }

注:

  • 写有两个参数,第二个参数可不写,第二个参数的作用是:在完成写数据的时候就会执行该函数。
  • setState 时是不会立即改变 this.state ,会在当前代码运行完成后,才去更新 this.state ,从而触发UI更新。

根据上面注意的第二条,可以进行改良,不使用对象的形式而是使用函数的形式,如下:

  1. class App extend React.Component {
  2. constructor(props){
  3. super(props);
  4. /*...*/
  5. }
  6. onClick = () => {
  7. this.setState((state) => ({n: this.state.n + 1})) //写
  8. }
  9. render(){
  10. return (
  11. /*...*/
  12. )
  13. }
  14. }

这种方式就是,当我想算的时候就会去执行,而不是对象的写法,需要代码运行完成才可以执行。

setState时会 shallow merge

即setState会自动将新state与旧state进行一级合并。

能修改this.state吗

能,但这是不守规矩!如:

  1. this.state.n += 1
  2. this.setState(this.state)

并没有人说不可以这样,虽然可以但这只是不遵守规矩的行为,请避免。