学习地址:https://www.bilibili.com/video/BV1wy4y1D7JT
官方文档:
组件实例三大属性之一:state
理解:
- state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)。
- 组件被称为‘状态机’,通过更新组件的state来更新对应的页面显示(重新渲染组件)。
注意事项:
- 组件中render方法中的this为组件实例对象。
- 组件自定义方法中的this为undefined,解决方法:
a.强制绑定this,通过函数对象的bind();
b.使用箭头函数形式。 - 状态数据不能直接修改或更新。setState();
<script type="text/babel">
class MyComponent extends React.Component{
constructor(prop){
super(prop);
this.state = {isHot:true};
//解决changeHot中this指向问题
this.changeHot = this.changeHot.band(this);
};
renter(){
return <h1 onClick={this.changeHot}>今天的天气很{this.isHot ? '炎热' : '寒冷'}</h1>
};
changeHot(){
//类中的方法默认开启严格模式所以changeHot中的this为undefined
console.log(this);
const isHot = this.state.isHot;
//状态(state)必须通过setState更新
this.setState({isHot:!isHot});
};
}
//渲染组件
ReactDOM.render(<MyComponent/>,document.getElementById('test'));
</script>
精简写法
<script type="text/babel">
class MyComponent extends React.Component{
state = {isHot:true};
renter(){
return <h1 onClick={this.changeHot}>今天的天气很{this.isHot ? '炎热' : '寒冷'}</h1>
};
//自定义方法使用赋值语句+箭头函数的形式
changeHot = ()=>{
const isHot = this.state.isHot;
//状态(state)必须通过setState更新
this.setState({isHot:!isHot});
}
}
</script>
组件三大属性之二:props
理解:
- 每个组件对象都会有props(properties的简写)属性。
- 组件标签的所有属性都保存在props中
作用
- 通过标签属性从组件外向组件内传递变化参数。
- 注意:组件内部不要修改props数据
编码操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="test"></div>
<div id="test1"></div>
<div id="test2"></div>
<!-- react核心库 -->
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<!-- react-dom用于支持react操作dom -->
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 引入babel 用于将jsx转成js -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.js"></script>
<!-- 引入prop-types 用于对标签属性进行限制 -->
<script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
<script type="text/babel">
class MyComponent extends React.Component {
constructor(props) {
// 构造器中是否接收props、是否传递给super,取决于是否希望在构造器中通过this访问props
super(props);
console.log('constructor', this.props);
}
// static 对类本身添加属性
// 对标签属性进行类型、必要性的限制
static propTypes = {
name: PropTypes.string.isRequired,//限制 name必传且为字符串
sex: PropTypes.string,//限制sex为字符串
age: PropTypes.number,//限制age为数字
// speak: PropTypes.func //限制speak为函数
}
// 指定默认标签属性值
static defaultProps = {
sex: '女',
age: 18
}
render() {
const { name, age, sex } = this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
)
}
};
// 对标签属性进行类型、必要性的限制
// MyComponent.propTypes = {
// name:PropTypes.string.isRequired,//限制 name必传且为字符串
// sex:PropTypes.string,//限制sex为字符串
// age:PropTypes.number,//限制age为数字
// speak:PropTypes.func //限制speak为函数
// }
// 指定默认标签属性值
// MyComponent.defaultProps ={
// sex:'女',
// age:18
// }
ReactDOM.render(<MyComponent name="赵小黑" sex="男" age={18} />, document.getElementById('test'));
const p = { name: '赵', sex: '男', age: 23 }
ReactDOM.render(<MyComponent {...p} />, document.getElementById('test1'));
// 函数式组件使用props
function Person(props) {
const { name, age, sex } = 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:'女',
// age:18
// }
ReactDOM.render(<Person name="赵大白" sex="女" age={18} />, document.getElementById('test2'));
</script>
</body>
</html>
组件三大属性之三ref
- 字符串形式 的ref(官网已不推荐使用)
<script type="text/babel">
// 创建组件
class MyComponent extends React.Component{
render(){
return(
<div>
<input ref="clickInput" type="text" placeholder="按钮触发" />
<button onClick={this.handleClick}>点击触发左侧</button>
<input ref="blurInput" onBlur={this.handleBlur} type="text" placeholder="失去焦点触发" />
</div>
)
};
//按钮点击事件
handleClick = ()=>{
alert(`提示数据:${this.refs.clickInput.value}`)
};
//失去焦点事件
handleBlur = ()=>{
alert(`提示数据:${this.refs.blurInput.value}`)
}
};
//渲染页面
ReactDOM.render(<MyComponent />,document.getElementById('test'));
</script>
- 回调函数形式的ref
<script type="text/babel">
// 创建组件
class MyComponent extends React.Component{
render(){
//内联形式定义
return(
<div>
<input ref={(currentNode)=>{this.clickInput = currentNode}} type="text" placeholder="按钮触发" />
<button onClick={this.handleClick}>点击触发左侧</button>
<input ref={currentNode => this.blurInput = currentNode} onBlur={this.handleBlur} type="text" placeholder="失去焦点触发" />
</div>
)
};
// 按钮点击事件
handleClick = ()=>{
alert(`提示数据:${this.clickInput.value}`)
};
// 失去焦点事件
handleBlur = ()=>{
alert(`提示数据:${this.blurInput.value}`)
}
};
// 渲染页面
ReactDOM.render(<MyComponent />,document.getElementById('test'));
</script>
如果ref回调函数是以内联函数的方式定义的,在更新过程中会被执行两次,第一次传入参数null,然后第二次会传入参数DOM元素。这是因为在每次渲染时会创建一个新的函数实例,所以React清空就得ref并且设置新的,通过将ref的回调函数定义成class的绑定函数的方式可以避免上述问题。
- React.createRef 形式的ref
React.createRef调用后可以返回一个容器,该容器可储存被ref所标识的节点该容器是‘专人专用’。
<script type="text/babel">
// React.reateRef形式
// 创建组件
class MyComponent extends React.Component {
//React.createRef调用后可以返回一个容器,该容器可储存被ref所标识的节点该容器是‘专人专用’。
input1 = React.createRef();
input2 = React.createRef();
// 按钮点击事件
handleClick = () => {
alert(`提示数据:${this.input1.current.value}`)
}
// 失去焦点事件
handleBlur = () => {
alert(`提示数据:${this.input2.current.value}`)
}
render() {
return (
<div>
<input ref={this.input1} type="text" placeholder="按钮触发" />
<button onClick={this.handleClick}>点击触发左侧</button>
<input ref={this.input2} onBlur={this.handleBlur} type="text" placeholder="失去焦点触发" />
</div>
)
}
}
// 渲染页面
ReactDOM.render(<MyComponent />, document.getElementById('test'));
</script>