目录
组件三大核心属性
组件中的state(状态)
注意:状态不可直接更改,要用setState去进行修改
状态在哪里,操作状态的方法就在哪里
- 借助构造器,初始化状态,读写状态
// 创建类式组件,继承react中的component
class Weather extends React.Component {
constructor(props){
// 有构造器必须有super,语法规定
super(props)
// state 需要一个对象来承接
this.state = { isHot: true }
}
render(){
const {isHot} = this.state
return <h1>今天天气{this.state.isHot ? '炎热': '凉爽'}</h1>
}
}
// 渲染到页面上
ReactDOM.render(<Weather/>,document.getElementById('test'))
绑定点击事件
- 绑定事件
注意:1. 绑定的onClick要用驼峰 2. 调用的函数要写成{demo} 不需要加括号
<script type="text/babel">
// 创建类式组件,继承react中的component
class Weather extends React.Component {
constructor(props){
// 有构造器必须有super,语法规定
super(props)
// state 需要一个对象来承接
this.state = { isHot: true }
}
render(){
// 读取状态
const { isHot } = this.state
// 绑定事件时不能用demo() 的形式,否则会默认执行,相当于把demo的返回值赋值给onclick
// return <h1 onClick={demo()}>今天天气{isHot ? '炎热': '凉爽'}</h1>
return <h1 onClick={demo}>今天天气{isHot ? '炎热': '凉爽'}</h1>
}
}
// 渲染到页面上
ReactDOM.render(<Weather/>,document.getElementById('test'))
// 绑定的点击事件
function demo(){
console.log('标题被点击了');
}
</script>
- 点击改变事件
目的获取实例身上的isHot然后去改变值
问题:获取不到实例身上的this
解决1:利用that,重新赋值that,成功获取
弊端:结构错误,一般只有两大块,一块是创建组件,一块是渲染组件
解决2:把changeWeather放在组件里面
错误:刚开始编译不报错,但点击时报错,changeWeather里面的this是undefined
原因:changeWeather不是实例调用的,而是render里面调用的,这里的this.changeWeather相当于直接调用
注意:类中的函数开启了局部的严格模式,所以this不指向window而是undefined
解决3:在实例身上添加changeWeather方法,changeWeather的来源是在原型链上
成功点击改变值
<script type="text/babel">
// 创建类式组件,继承react中的component
class Weather extends React.Component {
// 构造器只调用了一次
constructor(props){
super(props)
this.state = { isHot: true }
// 把原型链上的changeWeather 赋值给实例上的changeWeather,从而在下面this.changeWeather可以在实例身上找到changeWeather
// 重新把this指向实例
this.changeWeather = this.changeWeather.bind(this)
}
// render函数调用了 1+n次,第一次是初始化,n是状态更新的次数
render(){
// 读取状态
// 这里的this 指的是实例对象
const { isHot } = this.state
return <h1 onClick={this.changeWeather}>今天天气{isHot ? '炎热': '凉爽'}</h1>
}
// 绑定的点击事件
// changeWeather 点几次调用几次
changeWeather(){
// changeWeather放在哪里?——Weather的原型对象上,供实例使用
// 由于changeWeather是作为onClick的回调,所以不是实例调用的,是直接调用
// 类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
// console.log(this);
// 获取原来的isHot值
const isHot = this.state.isHot
this.setState({isHot: !isHot})
// 严重注意: 状态(state)不可直接更改
// this.state.isHot = !isHot 错误写法
}
}
// 渲染到页面上
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
state简写形式(开发常用)
注意:自定义函数需要写成赋值语句,且为箭头函数,否则会报错,找不到this
<script type="text/babel">
class Weather extends React.Component {
// 不需要外面传进来的参数赋值,可以直接写,不需要写在构造器内
state = {isHot: false, wind: '微风'}
render(){
const { isHot } = this.state
return <h1 onClick={this.changeWeather}>今天天气{isHot ? '炎热': '凉爽'}</h1>
}
// 自定义方法——赋值语句
// 使用箭头函数,箭头函数本身无this,向外找,此时this就是weather实例
changeWeather = () => {
const isHot = this.state.isHot
this.setState({isHot: !isHot})
}
}
// 渲染到页面上
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
组件中的props
注意:props是只读的,不能修改,如:this.props.name = 'jack'
props的基本使用
<script type="text/babel">
// 创建实例
class Person extends React.Component {
render(){
console.log('this:',this);
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
)
}
}
// 渲染到页面上,数值型的age可以写成 age={18}
ReactDOM.render(<Person name="li" age="18" sex="女"/>,document.getElementById('test'))
</script>
props的批量赋值
// 扩展运算符解构赋值
const p = {name: 'liu', age:'20', sex: '男'}
ReactDOM.render(<Person {...p}/>,document.getElementById('test2'))
标签限制(限制类型,必传,默认值)
注意:实例身上的propTypes中p是小写的,限制类型的PropTypes中的p是大写的
// 限制类型
Person.propTypes = {
name: PropTypes.string.isRequired, // isRequired必须传的值
age: PropTypes.number,
sex: PropTypes.string
}
// 设置默认值
Person.defaultProps = {
age: 18,
sex: '男'
}
一般写在定义实例的时候做限制
// 创建实例
class Person extends React.Component {
render(){
console.log('this:',this);
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
)
}
// 限制类型
static propTypes = {
name: PropTypes.string.isRequired, // isRequired必须传的值
age: PropTypes.number,
sex: PropTypes.string
}
// 设置默认值
static defaultProps = {
age: 18,
sex: '男'
}
}
补充说明constructor构造器
类中的构造器可以省略
constructor的作用:
- 对state的初始化,如:this.state = {isHot: true},但可以单独在构造器外面直接写 state = {isHot: true}
- 对事件的绑定,如:this.changeWeather = this.changeWeather.bind(this),但可以直接用箭头函数在构造器外面写
- 对于props,有传了props参数就必须要有super(props),否则props会是undefined。构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问到props
constructor(props){
super(props)
console.log('constructor',this.props);
}
constructor(props){
super()
console.log('constructor',this.props);
}
组件中的refs
简介:类似于vue中的ref,是标签的标识
refs:{key: value} key为绑定的ref值,value为所在的标签
注意:string类型的refs效率不高,在未来可能会被弃用
ref是字符串形式
ref为回调函数类型
注意:内联函数(即上例)的ref第一次渲染的时候会调用一次,之后更新的时候会调用两次,更新中的第一次为清空上一次的节点内容,此时的currentNode为null,第二次的时候才是正式更新,但是具体的影响并不大
如需解决:使用类函数调用(但是无关紧要)
<input ref={this.logInput} type="text" placeholder="点击提示数据" />
logInput = (e) => {
console.log('e',e);
}
使用createRef创建ref(常用)
创建的ref是“专人专用”的
<script type="text/babel">
// 创建实例
class Demo extends React.Component{
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 ref={this.myRef2} type="text" onBlur={this.showData2} placeholder="失去焦点提示数据" />
</div>
)
}
}
// 渲染到页面上
ReactDOM.render(<Demo />,document.getElementById('test1'))
</script>
注意:切勿过度使用ref,部分可以使用event.target获取节点信息
<script type="text/babel">
// 创建实例
class Demo extends React.Component{
myRef = React.createRef()
myRef2 = React.createRef()
showData = ()=>{
alert(this.myRef.current.value)
}
showData2 = (event)=>{
alert(event.target.value)
}
render(){
return(
<div>
<input ref={this.myRef} type="text" placeholder="点击提示数据" />
<button onClick={this.showData}>点击提示左侧</button>
<input type="text" onBlur={this.showData2} placeholder="失去焦点提示数据" />
</div>
)
}
}
// 渲染到页面上
ReactDOM.render(<Demo />,document.getElementById('test1'))
</script>