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

tech2022-09-13  106

前置简介

上一节(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 注意事项

this.state.n += 1 无效?

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

setState 会异步更新UI

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

this.setState(this.state)

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

函数组件注意事项

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

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

两种编程模型

Vue的编程模型

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

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

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

React的编程模型

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

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

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

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

最新回复(0)