React中数据分为两个部分
- 属性
- 状态 :频繁变化的就写成状态
属性(props)
props是正常从外部传入的,组件内部也可以通过一些方式来初始化的设置,属性不能被组件自己更改,但是你可以通过父组件主动重新渲染的方式来传入新的 props
属性是描述性质、特点的,组件自己不能随意更改。
1、在使用一个组件的时候,可以把参数放在标签的属性当中,所有的属性都会作为组件 props 对象的键值。通过箭头函数创建的组件,需要通过函数的参数来接收props:
import React , {Component} from 'react';
import ReactDOM from 'react-dom'
class Title extends Component {
render (){
return(
// class类组件通过this.props.属性名,获取标签内定义的属性值
<p> 欢迎学习 {this.props.name} </p>
)
}
}
// 函数式组件通过props.属性名,获取标签内定义的属性值
const Hello = (props) =>{
return <p> {props.name} 是一个库</p>
}
class App extends Component{
render (){
return (
<div>
<Title name="react"></Title>
<Hello name="react.js"></Hello>
</div>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')
)
2、设置组件的默认props
class Title extends Component {
// 使用类创建的组件,直接在这里写static方法,创建defaultProps
static defaultProps = {
name: 'React'
}
render (){
return(
// class类组件通过this.props.属性名,获取标签内定义的属性值
<p> 欢迎学习 {this.props.name} </p>
)
}
}
// 函数式组件通过props.属性名,获取标签内定义的属性值
const Hello = (props) =>{
return <p> {props.name} 是一个库</p>
}
// 使用箭头函数创建的组件,需要在这个组件上直接写defaultProps属性
Hello.defaultProps = {
name: 'React.js'
}
class App extends Component{
render (){
return (
<div>
{/* 由于设置了defaultProps, 组件标签属性值也能正常运行,如果传递了就会覆盖defaultProps的值 */}
<Title></Title>
<Hello></Hello>
</div>
)
}
}
3、props.children
我们知道使用组件的时候,可以嵌套。要在自定义组件的使用嵌套结构,就需要使用 props.children。
import React ,{ Component } from 'react';
import ReactDOM from 'react-dom'
class Child extends Component {
render(){
return (
<div> 这里是react子组件 </div>
)
}
}
class App extends Component{
render(){
return (
<div>
<h1>这里是App组件 {this.props.name} </h1>
{/* react中插槽的使用方式 */}
{ this.props.children }
</div>
)
}
}
ReactDom.render(
<App name="欢迎">
<Child/> {/* App组件若不使用props.children,Child组件不会被解析 */}
</App>,
document.getElementById('root')
)
4、使用prop-types检查props(属性验证)
React其实是为了构建大型应用程序而生, 在一个大型应用中,根本不知道别人使用你写的组件的时候会传入什么样的参数,有可能会造成应用程序运行不了,但是不报错。为了解决这个问题,React提供了一种机制,让写组件的人可以给组件的props设定参数检查,需要安装和使用prop-types:
- 安装包文件
$ npm i prop-types -S
- 使用方法
//引入文件
import PropTypes from 'prop-types'
const Hello = (props) =>{
return <p> {props.name} 是一个库</p>
}
Hello.defaultProps = {
name: 'React.js'
}
// 使用: 组件名.propTypes
Hello.propTypes = {
// 类的属性: 类的属性类型
name: PropTypes.string //设置为字符串类型
}
class App extends Component{
render (){
return (
<div>
<Title></Title>
<Hello name={1000}></Hello>{/* 设置属性值传入为Number类型*/}
</div>
)
}
}
- 结果
状态(state)
状态就是组件描述某种显示情况的数据,由组件自己设置和更改,也就是说由组件自己维护,使用状态的目的就是为了在不同的状态下使组件的显示不同
1、定义state
- 方法一:状态的实例属性定义
import React , {Component,Fragment} from 'react';
import ReactDOM from 'react-dom';
class App extends Component{
//使用state定义
state={
name:"react",
}
render(){
return (
<Fragment>
<p>欢迎学习 {this.state.name} </p>
</Fragment>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')
)
- 方法二:在构造函数 constructor 中定义state状态
class App extends Component{
constructor( props ){
//props 是用来继承属性的,可不写
super( props)
this.state = {
msg:'state的构造器函数定义'
}
}
render(){
return (
<Fragment>
<p>这是 {this.state.msg} </p>
</Fragment>
)
}
}
2、setState
this.props和this.state是纯js对象,在vue中,data属性是利用Object.defineProperty处理过的,更改data的数据的时候会触发数据的getter和setter,但是React中没有做这样的处理,如果直接更改的话,react是无法得知的,所以,需要使用特殊的更改状态的方法setState。
通过添加点击事件来改变状态,控制元素的显示:
import React , {Component,Fragment} from 'react';
import ReactDOM from 'react-dom';
class App extends Component{
constructor( ){
super( )
this.state = {
name:'react',
msg:false,
}
}
handleClick(){
this.setState({
// 属性: 属性的新值
msg:!this.state.msg,
})
// this.setState(arg1,arg2)
/*
arg1
1. 可以是对象
2. 也可以是函数,但是函数一定要有return,return 一个对象
3. 上述是对象写法,函数可以写成
this.setState(( ) => {
return {
msg:!this.state.msg,
}
})
arg2
1. 是一个回调函数
2. 这个回调函数可以写,也可以不写
*/
}
render(){
return (
<Fragment>
<p>这是 {this.state.name} </p>
{/* 通过上述函数定义事件处理函数,在触发事件时需要将丢失的this指向找回 */}
<button onClick={ this.handleClick.bind(this) } > 点击收藏</button>
<p> {this.state.msg ?'❤️取消':'?收藏' } </p>
</Fragment>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')
)
//另外上述方法绑定事件处理函数会丢失this指向,我们可以通过箭头函数来定义事件处理函数,这样this指向不会丢失
//箭头函数定义事件处理函数
handleClick= ( ) => {
this.setState({
msg:!this.state.msg,
})
}
//
render(){
return (
<Fragment>
<p>这是 {this.state.name} </p>
{/* this指向不会丢失 */}
<button onClick={ this.handleClick } > 点击收藏</button>
<p> {this.state.msg ?'❤️取消':'?收藏' } </p>
</Fragment>
)
}
属性vs状态
-
相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)
-
不同点:
a、属性能从父组件获取,状态不能
b、属性可以由父组件修改,状态不能
c、属性能在内部设置默认值,状态也可以
d、属性不在组件内部修改,状态要改
e、属性能设置子组件初始值,状态不可以
f、属性可以修改子组件的值,状态不可以
g、state 的主要作用是用于组件保存、控制、修改自己的可变状态。state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState方法进行更新,setState 会导致组件的重新渲染。 -
props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props,否则组件的 props 永远保持不变。
-
没有 state 的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。
-
react性能优化一个方案: 就是多使用无状态组件( 函数式组件 )