💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 1. setState的简单实践和理解 比如说,我们需要定义一个列表组件。当点击奇数列表的时候随机调换一下顺序;当点击偶数列表的时候在其后加=和不加=号之间切换。 ## 1.1 代码实现 ~~~html <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> ) } } ~~~ 运行后可以在控制台看见打印的实例: ![](https://img.kancloud.cn/f3/df/f3dfc8561b412d877b015b43208778b1_994x272.png) 也就是在自定义组件,继承自`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 ~~~ ![](https://img.kancloud.cn/ae/19/ae19201f3f468faa9d9782ffe8fa7253_290x218.png) 点击按钮可以将用户年龄增加。值得注意的是,这里使用`this.setState`来更新的时候,并不需要将没有发生改变的用户`name`字段重新赋值。这里也可以发现,`setState`不是覆盖,而是对比差异,然后更新。