1. setState的简单实践和理解
比如说,我们需要定义一个列表组件。当点击奇数列表的时候随机调换一下顺序;当点击偶数列表的时候在其后加=和不加=号之间切换。
1.1 代码实现
<body>
<div id="test"></div>
<script crossorigin src="./js/react.development.js"></script>
<script crossorigin src="./js/react-dom.development.js"></script>
<script src="./js/babel.min.js"></script>
<script type="text/babel">
var root = document.getElementById("test")
class MyElement extends React.Component {
constructor() {
super();
this.state = {
datas: ["张三", "李四", "王五"]}
}
userClick(index) {
let flag = index % 2 === 0
if (flag) {
// 奇数列表项乱序切换
let temp_list = []
for (let i = 0; i < this.state.datas.length; i++) {
if (i % 2 === 0) {
temp_list.push(this.state.datas[i])
}
}
temp_list.sort(() => Math.random() - 0.5)
let temp_data = []
let j = 0
for (let i = 0; i < this.state.datas.length; i++) {
if (i % 2 === 0) {
temp_data.push(temp_list[j])
j++
} else {
temp_data.push(this.state.datas[i])
}
}
this.setState({
datas: temp_data})
} else {
// 等号和没等号之间切换
let temp_list = []
let switchFlag = false
if(this.state.datas[1] != null && this.state.datas[1].endsWith("=")) {
switchFlag = true
}
for (let i = 0; i < this.state.datas.length; i++) {
if (i % 2 !== 0) {
if (!switchFlag) {
temp_list.push(this.state.datas[i] + "=")
} else {
temp_list.push(this.state.datas[i].substring(0, this.state.datas[i].length - 1))
}
} else {
temp_list.push(this.state.datas[i])
}
}
this.setState({
datas: temp_list})
}
}
render() {
return (
<ul>
{
this.state.datas.map((item, index) => {
return <li key={
index} onClick={
() => {
this.userClick(index)
}}>{
item}</li>
})
}
</ul>
)
}
}
ReactDOM.render(<MyElement/>, root)
</script>
</body>
注意到这里更新数据的时候使用了:
this.setState({
datas: temp_list})
且数据声明也放置在了构造器中:
constructor() {
super();
this.state = {
datas: ["张三", "李四", "王五"]}
}
那么,为什么需要这么写?
1.2 分析
对于下面极简的类组件:
class MyElement extends React.Component {
constructor() {
super();
console.log(this)
}
render() {
return (
<div>Hello!</div>
)
}
}
运行后可以在控制台看见打印的实例:
也就是在自定义组件,继承自React.Component
的时候,默认就带有一个为null
的属性state
。如果我们需要做到数据的动态更新,就需要使用state
这个属性,并且在使用的时候,需要使用setState
来进行更新。
2. 函数组件state、类组件state
2.1 函数组件state
比如下面定义一个简单的函数组件:
function Demo() {
return (
<div>Hello!</div>
)
}
经过babel
翻译后为:
"use strict";
function Demo() {
return /*#__PURE__*/React.createElement("div", null, "Hello!");
}
我们知道在Rect
函数组件中只有props
,没有refs
以及state
。如果需要使用state
需要引入外部的钩子。比如:
function Demo(props) {
console.log(props)
const [flag, setFlag] = useState(false)
const handleClick = () => {
setFlag(!flag)
}
return (
<div onClick={
handleClick}>Hello! flag is {
flag ? 'true': 'false'}</div>
)
}
root.render(
<Demo name={
"张三"} />
);
在申明state
变量的时候,就指定了变量名和更新这个值状态的方法,即:
const [flag, setFlag] = useState(false)
2.2 类组件state
import React from "react";
class ClassState extends React.Component{
constructor() {
super();
this.state = {
name: '李四', age: 12}
}
handleClick = () => {
const pre_age = this.state.age
this.setState({
age: pre_age + 1})
}
render(){
const {
name, age} = this.state
return (
<div>Hello! class state. Info: <br/>
<p>姓名:{
name}</p>
<p>年龄:{
age}</p>
<button onClick={
this.handleClick}>点击修改</button>
</div>
)
}
}
export default ClassState
点击按钮可以将用户年龄增加。值得注意的是,这里使用this.setState
来更新的时候,并不需要将没有发生改变的用户name
字段重新赋值。这里也可以发现,setState
不是覆盖,而是对比差异,然后更新。