组件实例的三大核心属性——statepropsrefs
Posted MaNqo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组件实例的三大核心属性——statepropsrefs相关的知识,希望对你有一定的参考价值。
组件实例的三大核心属性
一、state
state的理解
一个组件如果是有状态(state)的,那么这个组件就是复杂组件。也就是如果一个组件没有state,这个组件就是简单组件。
-
state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)
-
组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)
组件的状态里面存着数据,通过改变数据更新组件的状态来更新着页面的展示。
但我们创建类式组件的时候,通过把组件实例对象打印出来,可以看到它的state的值为null的,这个时候我们可以通过对state的操作来完成一些事情。
案例:
下面通过类式组件来实现下面这个案例;
在类中,创建子类要通过调用super来继承父类的东西,而props
这个参数也是必不可少的。
在类中的方法默认开启了局部的严格模式,由于changeWeather
是作为onClick
的回调,所以不是通过实例回调,而是直接调用的,因此要在constructor
中先将changeWeather
中this的指向强制绑定为组件的实例对象,以便后续对这个实例对象进行操作。
最后在render中设置一个点击事件来调用changeWeather
这个函数。
class Weather extends React.Component
constructor(props)
super(props);
this.state = isHot: false ;
this.demo = this.changeWeather.bind(this);
render()
const isHot = this.state;
return <h1 onClick=this.demo>今天天气很isHot ? '炎热' : '凉爽'</h1>
changeWeather()
const isHot = this.state.isHot;
console.log(this);
this.setState( isHot: !isHot );
ReactDOM.render(<Weather />, document.getElementById('test'));
在这个过程中,构造器被调用了一次,而render被调用了1+n次,1是初始化组件的那一次,而n就是状态更新的次数。
这里不可以直接通过this.state.isHot = !isHot
来修改state的值,因为如果这样子就能够修改的话,把state换做是任何一个单词都可以这样子进行修改,那么state也就没有什么特别的了。
因此,修改状态(state)应该是借助React的一个内置API(setState)
去进行修改。
state的简写方式
对上面案例的这份代码进行简化,在开发中一般都用简化后的写法。
直接通过state = isHot: false ;
来初始化状态
将changeWeather
用箭头函数自定义方法(要用赋值语句的形式+箭头函数),使这个this的指向Weather
的实例对象。
class Weather extends React.Component
state = isHot: false ;
render()
const isHot, wind = this.state;
return <h1 onClick=this.changeWeather>今天天气很isHot ? '炎热' : '凉爽'</h1>
changeWeather = () => // 箭头函数
const isHot = this.state.isHot;
this.setState( isHot: !isHot );
二、 props
props的理解
props可以接收传递给数组的数据(任何类型都可)
- 每个组件对象都会有props属性
- 组件标签的所有属性都保存在props中
引入prop-types
用于对组件标签属性进行限制,此时全局多了一个PropTypes
对象。
<script type="text/javascript" src="../js/prop-types.js"></script>
在render中传入的属性值后,打印Person实例对象,可以发现传入的值就在props这个属性中。
因此我们就可以通过这个props来实现一些功能。通过propTypes
来对标签属性进行类型、必要性的限制,然后通过defaultProps
来对这个默认值进行设置,即当没有传入sex
时,sex
默认为无。
这里的...p
运用到了扩展属性,将对象的所有属性通过props传递。
class Person extends React.Component
render()
console.log(this);
const name, age, sex = this.props;
return (
<ul>
<li>姓名:name</li>
<li>性别:sex</li>
<li>年龄:age</li>
</ul>
)
static propTypes =
name: PropTypes.string.isRequired,
age: PropTypes.number,
speak:PropTypes.func // 限制speak为函数
Person.defaultProps =
sex: '无'
const p = name: "mannqo", age: 18 ;
console.log(...p);
ReactDOM.render(<Person ...p />, document.getElementById('test'));
props
(1)只读,即无法直接进行修改,在组件内部不要修改props数据;(2)通过标签属性从组件外向组件向组件内传递变化的数据。简写方式:静态属性,所谓的简写其实就是通过static把限制条件从类的外侧移动到类的里面。
在React中,构造函数仅用于以下两种情况:
- 通过给
this.state
复制对象来初始化内部state - 为事件处理函数绑定实例
在类式组件的构造器中,如果没有传props,直接打印this.props
的值为undefined。因此如果需要在构造器中通过this拿到props
的话就应该接收props并且传递给super。
constructor(props)
super(props);
console.log(this.props);
函数式组件使用props:(函数式组件也只可以使用props)
function Person(props)
const name, age, sex = props;
return (
<ul>
<li>姓名:name</li>
<li>性别:sex</li>
<li>年龄:age</li>
</ul>
)
Person.propTypes =
name: PropTypes.string.isRequired,
sex: PropTypes.string.isRequired,
Person.defaultProps =
sex: '女',
age: 18
ReactDOM.render(<Person name='mannqo' />, document.getElementById('test'));
三、refs
组件类的标签可以定义refs
属性来标识,但是ref不能过度使用
1. 字符串形式的ref
string类型的ref存在着一些效率上的问题,一般不推荐使用(官网说它过时了)。
实现下面这段代码:
<input ref="input1" type="text" />
就可以看到实例对象中的refs不再是空,而是refs: input1: input
;这样就不需要再给每一个标签设置一个id属性,也省下了document.getElementById
这个语句,直接用this.refs.input1
就可以获取到这个标签了。
2.回调函数形式的ref
如果ref
回调函数是以内联函数的方式定义的,它再更新过程中会被执行两次,第一次传入参数null
,第二次传入参数DOM元素。因为每次渲染时会创建一个新的函数实例,React会清空旧的ref并且设置新的,通过ref的回调函数定义成class的绑定函数的方式可以避免上述问题,(但是这个问题可以忽略),实际开发中内联函数的形式写的比较多。
// 内联函数 《最常用》
<input ref=a => this.input1 = a; console.log(a) type="text" />
// 函数 不会重复调用
<input ref=this.saveInput type="text" />
jsx
注释方式:/* xxx */
3. createRef
的使用
React.createRef
调用后可以返回一个容器,该容器可以存储被ref所标识的节点。且这个容器只能存一个节点。通过this.myRef.current
可以找到ref绑定的那个节点。
myRef = React.createRef();
showInput=(event)=>
console.log(event); // 这个event是按钮的绑定事件
console.log(this.myRef.current.value)
render()
return (
<div>
<input ref=this.myRef type="text" />
<button onClick="showInput"></button>
</div>
)
4. 事件处理
-
通过
onXxx(如onClick)
属性指定事件处理函数(注意大小写)- React使用的是自定义合成时间,而不是原生DOM事件 —— 兼容性
- React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)—— 高效性
-
通过
event.target
得到发生事件的DOM元素对象,在调用函数的时候就会自动把这个事件传给这个函数。在发生事件的元素就是这个元素的时候就可以省略ref。但如果是要通过按钮来监听输入框的话(上一个例子)就没办法直接用这种方式实现。showDatas = (event) => console.log(event); render() return ( <input type="text" onBlur=this.showDatas /> )
总结
- 组件中render方法中的this为组件实例对象
- 组件只定义的方法中的this为undefined时,可以通过函数对象
bind()
强制绑定this,或者箭头函数 - 状态数据不能直接修改或更新,而是用
setState
去修改 - 组件内部不能修改
props
数据 ref
不能过度使用
以上是关于组件实例的三大核心属性——statepropsrefs的主要内容,如果未能解决你的问题,请参考以下文章
React面向组件编程 - 基本理解和使用 - 组件三大核心属性state-props-refs - 事件处理 - 非受控组件 - 受控组件 - 高阶函数 - 函数柯里化