文章目录
- state 介绍
- 准备代码
- state 初始化
- 读取 state
- 改变类式组件中自定义方法的 this 指向
- 更改设置 state
- 完整代码(state 标准写法)
- state 的简写方式
state 介绍
state 即状态,通俗的讲,也是数据,对于组件而言我总结出以下几点:
- 状态 state 是组件私有的,完全受控于当前组件。除了拥有并设置了它的组件,其他组件都无法访问。
- state 用来管理组件内部的数据,数据的改变就是状态。
- 尽管 state 是 React 本身设置的,且都拥有特殊的含义,但我们可以随意更改设置 state,通常我们会将 state 初始化为一个对象,使用起来更灵活方便。
可能与组件实例的另外一大属性 props 相比较来讲更容易理解,state 用来管理组件内部的数据,props 用来管理组件外部传进来的数据。
准备代码
先准备一个基础类式组件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="app"></div>
<!-- step01: 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- step02: 引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- step03: 引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel"> /* 此处一定要写babel */
// 1. 创建类式组件
class Weather extends React.Component {
constructor(props) {
super(props);
}
render() {
return <h2 onClick={this.changeWeather}>今天天气很凉爽,微风。</h2>
}
}
// 渲染组件到页面
ReactDOM.render(<Weather/>, document.getElementById('app'));
</script>
</body>
</html>
下文的代码片段都可以添加到该组件,来运行以验证结果。
state 初始化
在类式组件的构造器中初始化状态 state,代码片段如下:
constructor (props) {
super(props);
// 初始化状态 state
this.state = {isHot: true, wind: '微风'};
// TODO 其他代码……
}
注意:构造器中是唯一可以通过 this.state = {...}
的形式赋值的地方。
读取 state
- 在 render 方法中,可通过 this 直接读取,代码片段如下:
render() {
const {isHot, wind} = this.state;
return <h1>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>;
}
- 在用户自定义的类的方法中,无法通过 this 直接读取,代码片段如下:
// 定义类的方法
changeWeather() {
console.log(this); // 控制台输入:undefined
}
// 调用自定义方法
render() {
const {isHot, wind} = this.state;
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>;
}
将代码文件通过 Live Server 在浏览器中打开, 点击 h1
标题文本,浏览器控制台输出如下:
此时自定义方法中的 this 是
undefined
,原因如下:
- 由于 changeWeather 是作为 onClick 的回调,所以不是通过实例调用的,是直接调用;
- 类中的方法默认开启了局部的严格模式,所以 changeWeather 中的 this 为 undefined。
如何解决上面的问题呢?其实很简单,只要想办法让自定义方法中的 this 指向组件实例对象即可。
改变类式组件中自定义方法的 this 指向
在组件的构造器中通过 bind
方法来改变类中自定义的方法的 this 指向,并将其指向组件实例。代码片段如下:
constructor (props) {
super(props);
// 初始化状态 state
this.state = {isHot: true, wind: '微风'};
// 改变 changeWeather 中 this 指向
this.changeWeather = this.changeWeather.bind(this);
}
将代码文件通过 Live Server 在浏览器中打开, 点击 h1
标题文本,浏览器控制台输出如下:
更改设置 state
- 不能直接修改 state。
// 下面这样的写法是错误的
this.state.isHot = false;
通过上面的方式虽然不会报错,但是不会重新渲染组件。
- state 必须通过 setState 进行合并更新。
当调用 setState() 的时候,React 会把你提供的对象合并到当前的 state,而不是替换。
changeWeather() {
// 获取原来的 isHot 值
const isHot = this.state.isHot;
// 状态必须通过 setState 进行更新,且更新是一种合并,不是替换。
this.setState({isHot: !isHot});
}
此时代码文件通过 Live Server 在浏览器中打开, 点击 h1
标题文本,就会交替显示“炎热”和“凉爽”。
完整代码(state 标准写法)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="app"></div>
<!-- step01: 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- step02: 引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- step03: 引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel"> /* 此处一定要写babel */
// 1. 创建类式组件
class Weather extends React.Component {
constructor(props) {
super(props);
// 初始化状态 state
this.state = {isHot: true, wind: '微风'};
// 改变 changeWeather 中 this 指向
this.changeWeather = this.changeWeather.bind(this);
}
render() {
const {isHot, wind} = this.state;
return <h2 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}。</h2>;
}
changeWeather() {
// 获取原来的 isHot 值
const isHot = this.state.isHot;
// 状态必须通过 setState 进行更新,且更新是一种合并,不是替换。
this.setState({isHot: !isHot});
}
}
// 渲染组件到页面
ReactDOM.render(<Weather/>, document.getElementById('app'));
</script>
</body>
</html>
state 的简写方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="app"></div>
<!-- step01: 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- step02: 引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- step03: 引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel"> /* 此处一定要写babel */
// 1. 创建类式组件
class Weather extends React.Component {
// 初始化 state
state = {isHot: true, wind: '微风'};
// 自定义方法
changeWeather = () => {
const isHot = this.state.isHot;
this.setState({isHot: !isHot});
}
render() {
const {isHot, wind} = this.state;
return <h2 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}。</h2>;
}
}
// 渲染组件到页面
ReactDOM.render(<Weather/>, document.getElementById('app'));
</script>
</body>
</html>
简写方式解析,实际上都是用了 js 语言的本身的一些特性:
- 简写后的初始化 state,就是类中通过赋值语句定义属性的语法,这种方式定义的属性,会被放到类的实例对象上;
- 简写后的自定义方法是结合了赋值语句和箭头函数的特性,复制语句和初始化 state 思路一样,箭头函数特点之一就是它内部没有自己的 this ,而是指向箭头函数外部的对象 ,而赋值语句定义的属性又被放到了类的实例对象上,从而也解决了自定义方法 this 指向的问题。