React笔记之组件-props和state的使用(3)

前置简介

上一节(https://juejin.im/post/6867429672347500551)说了如何使用props,这一节介绍一下state的使用。

代码在:https://codesandbox.io/s/dawn-shape-bofqp?file=/src/index.js

index.js

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

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

在类组件中使用state

上面的index.js中的Son组件,有如下代码:

  add() {
    this.setState({ n: this.state.n + 1 });
  }

通过调用this.setState来对n数字就行+1操作,

这里为什么不可以直接通过 this.state.n++ 或者 this.state.n = this.state.n + 1 来改变呢?

因为React其实并没有去监听this.state.n这个属性,即使这个属性发生了变化,React也是无感知的,这里和Vue以及Angular是有区别的,

所以我们需要调用setState方法对React进行通知,使其刷新视图,

看下方代码:

  add() {
  	this.state.n += 1
    this.setState(this.state);
  }

读者可以用这段代码去实验一下,是可以使得视图刷新的,但是我们并不推荐这么做,因为React要遵循一个原则,数据不可变性,以前的对象不要再去改动它了,生成一个新的对象,如下:

  add() {
    this.setState({n: this.state.n + 1});
  }

尽管上述的写法已经没有问题了,但是如果我们想在setState方法后打印log最新的值,我们一般会这么写:

 add() {
    this.setState({n: this.state.n + 1});
    console.log(this.state.n)
 }

但是这种写法其实并不会生效,因为setState方法是异步去执行的,所以我们要换一种写法:

 add() {
    this.setState((state) => {
    	const n = state.n + 1
        console.log(n)
    	return {n: n}
    });
 }

我们在this.setState参数中传递了一个函数,这个函数中我们对 n 这个数字进行操作,并进行打印log,

最后返回一个新的对象用来告诉React,这么做的好处是方便我们在赋值操作的前后做一些额外处理,并且不会因为setState方法执行的异步造成一些困惑。

在函数组件中使用state

上面的index.js中的Grandson组件,有如下代码:

  const [n, setN] = React.useState(0);

React.useState 返回两个值,一个是 n 本身的值也就是方法中的 0,另外一个是setN方法,用来改变 n 的值,

所以在函数组件中通过 React.useState 获取到的第二个值,来操作一个属性的值就好。

  // 这里是析构赋值,React.useState(0)返回了一个数组,第一个是值本身,第二个是修改值的方法,接收的属性名可以自己定义
  const [n, setN] = React.useState(0);

注意 setN 并不是直接去修改 n 的值的,而是生成了一个新的state,遵循了数据不可变性原则,这个后面会详细来解释。

类组件 setState 注意事项

  1. this.state.n += 1 无效?

    其实 n 已经改变了,只是UI不会自动更新, 调用 setState 才会触发UI更新 (并且更新是异步的),因为 React 没有像 Vue 监听 data 一样监听 state,所以需要手动调用 setState 去通知React进行更新操作。

  2. setState 会异步更新UI

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

  3. this.setState(this.state)

    这种方式虽然也可以改变数据,但是React希望我们不要更改旧state,所以不推荐使用,常用的代码是 setState({n:state.n + 1})

函数组件注意事项

  1. 跟类组件相似,需要通过setX(新值)来更新UI。

  2. 跟类组件不同的地方,没有this,一律使用参数和变量。

两种编程模型

Vue的编程模型

一个对象对应一个虚拟DOM,当对象的属性改变时,把属性相关的DOM节点全部更新。

PS(Vue为了其他考量,也引入了虚拟DOM和DOM diff)。

例如将 n 放在模板中,后续对 n 做直接更改,那么视图中的 n 也跟着做相应的更改。

React的编程模型

一个对象,对应一个虚拟DOM。

另一个对象,对应另一个虚拟DOM。

对比两个虚拟DOM,找出不同之处(DOM Diff) 最后局部更新DOM。

例如刚开始创建了一个 n 对象,放到视图中,后面要新创建一个 n 对象,再放到视图中,React进行对比,做出相应的改变。

猜你喜欢

转载自blog.csdn.net/cainiao1412/article/details/108375098