在React框架中定义了一个状态(State) 概念, 并通过状态(State)来实现React组件的状态机特性。
“状态机” 特性: 就是指 组件通过与用户的交互, 更新实现不同的状态,通过渲染UI保证用户界面和数据一致性 (不需要操作DOM)
应用场景:组件的内容需要根据数据的刷新而刷新
创建方法: 在类的构造函数中定义
this.state={
属性名:属性值
…
}
this:代表当前组件
state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
改变state属性状态: setState()方法
//1.创建组件
class Weather extends React.Component{
constructor(props){
super(props)
//初始化状态
this.state = {isHot:false,wind:'微风'}
}
render(){
//读取状态
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
changeWeather(){
//changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
//由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
//类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
//获取原来的isHot值
const isHot = this.state.isHot
//注意:状态(state)不可直接更改!!!
//this.state.isHot = !isHot //这是错误的写法
//注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
this.setState({isHot:!isHot})
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
问题:会报错 state状态未定义。 即自定义的方法中this为undefined,该this指向存在错误
解决this指向问题:
1、强制绑定this: 通过函数对象的bind()
//1.创建组件
class Weather extends React.Component{
//构造器调用几次? ———— 1次
constructor(props){
super(props)
//初始化状态
this.state = {isHot:false,wind:'微风'}
this.changeWeather = this.changeWeather.bind(this)
}
//render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数
render(){
//读取状态
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//changeWeather调用几次? ———— 点几次调几次
changeWeather(){
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
2、箭头函数 (推荐使用)
//1.创建组件
class Weather extends React.Component {
//初始化状态
state = { isHot: false, wind: '微风' }
render() {
const { isHot, wind } = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//自定义方法————要用赋值语句的形式+箭头函数
changeWeather = () => {
const isHot = this.state.isHot
this.setState({ isHot: !isHot })
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather />, document.getElementById('test'))
React框架定义了一个 Props 的概念, 专门用来实现React函数组件接受参数的输入。而React类组件使用React Props参数的方法:React框架为类组件定义了一个默认Props – defaultProps,使用defaultProps默认值来实现React Props应用
props属性:从组件外部向组件内部传递变化了的数据,在组件内部不能改变它的值。但是有一种情形它貌似可变,即是将父组件的state作为子组件的props,当父组件的state改变,子组件的props也跟着改变
1、读取props中的属性值:this.属性名
2、向props中传值:
<组件名 属性名1='值1' 属性名2='值2'/ >
<组件名 {...实例对象} />
3、设置组件的默认值:组件名.defaultProps={ 属性名:默认值 }
4、属性值的类型限制、必要性限制:
导入类型、必要性限制的库:prop-type.js
格式:
类名.propTypes={ 属性名:限制条件 }
static proTypes={ 属性名:限制条件 }
注意:
在类外定义的方式:
//创建组件
class Person extends React.Component{
render(){
const {name,age,sex} = this.props
//props是只读的
//this.props.name = 'jack' //此行代码会报错,因为props是只读的
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//对标签属性进行类型、必要性的限制
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
speak:PropTypes.func,//限制speak为函数
}
//指定默认标签属性值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
//渲染组件到页面
ReactDOM.render(<Person name="sam" speak={speak}/>,document.getElementById('test1'))
ReactDOM.render(<Person name="tom" age={20} sex="女"/>,document.getElementById('test2'))
const p = {name:'老刘',age:18,sex:'女'}
// ReactDOM.render(,document.getElementById('test3'))
ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
function speak(){
console.log('我说话了');
}
在类中定义的方式:(简化)
//创建组件
class Person extends React.Component{
constructor(props){
//构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
super(props)
console.log('constructor',this.props);
}
//对标签属性进行类型、必要性的限制
static propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
}
//指定默认标签属性值
static defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
render(){
const {name,age,sex} = this.props
//props是只读的
//this.props.name = 'jack' //此行代码会报错,因为props是只读的
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//渲染组件到页面
ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
函数式组件使用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, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
}
//指定默认标签属性值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
//渲染组件到页面
ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
props和state属性的区别:
在React数据流中,父子组件唯一的交流方式是通过props属性;如果要修改子组件,通过修改父组件的属性,更新达到子组件props属性的值,重新渲染组件以达到视图的更新。但是,有些场景需要获取某一个真实的DOM元素来交互,比如文本框的聚焦、触发强制动画等。
比如:1、给DOM元素添加ref属性,2、给类组件添加ref属性
refs属性:读取组件内部的标签的值
在组件内部可以给标签定义ref属性:用于标识标签
使用 ‘this.refs.标签的ref属性名’ 就可以获取到对应的标签
用法:
字符串形式的 ref (过时):
<input ref="input1" />
回调形式的 ref:
<input ref={c => this.input1 = c } />
createRef创建 ref容器(推荐)(版本>=React 16.3)·:
myRef = React.createRef();
<input ref={this.myRef}/>
ref属性 可以挂到任何组件上,可以挂到组件上,也可以是dom元素上:
creatRef的使用:
//创建组件
class Demo extends React.Component{
/*
React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
*/
myRef = React.createRef()
myRef2 = React.createRef()
//展示左侧输入框的数据
showData = ()=>{
alert(this.myRef.current.value);
}
//展示右侧输入框的数据
showData2 = ()=>{
alert(this.myRef2.current.value);
}
render(){
return(
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧的数据</button>
<input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo/>,document.getElementById('test'))