前言
组件的三大核心属性
内容
state
定义一个展示天气信息组件,通过点击切换天气信息
理解
- state是组件对象最重要的属性,值是对象(可以包含多key-value组合)
- 组件被称为
状态机
,通过更新组件的state来重新渲染组件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test">
</div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
class Weather extends React.Component {
//调用1次
constructor(props) {
super(props);
//初始化状态
this.state = { isHot: true };
//解决changeWeather的指向问题
this.changeWeather = this.changeWeather.bind(this)
}
//调用次数1 n 1是初始化,n是状态更新
render() {
console.log(this)
//读取状态
const {isHot} = this.state
return (
<div>
<h1 onClick={this.changeWeather}>今天天气 {isHot ? '热热' : '不热热'}</h1>
</div>
);
}
//点击几次调用几次
changeWeather(){
//状态不可直接更改需要借助内置方法(setState)进行更改
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
</body>
</html>
简写
代码语言:javascript复制<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test">
</div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
class Weather extends React.Component {
render() {
const {isHot} = this.state
return (
<div>
<h1 onClick={this.changeWeather}>今天天气 {isHot ? '热热' : '不热热'}</h1>
</div>
);
}
//赋值语句 箭头函数
changeWeather = () => {
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
</body>
</html>
注意点
代码语言:javascript复制1. 组件中的render方法中的this为组件实例对象
2. 组件中自定义的方法中的为undefined,如何解决?
2.1 前置绑定this:通过函数对象的bind()
2.2 赋值语句 箭头函数
3. 状态数据,不能直接修改或更新,需通过setState来变更
props
自定义用来显示一个人员信息的组件
- 姓名必须指定,且为字符串类型;
- 性别为字符串类型,如果性别没有指定,默认为男
- 年龄为字符串类型,且为数字类型,默认值为18
理解
- 每个组件对象都会有props(properties)属性
- 组件标签的所有属性都保存在props中
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<div id="test1"></div>
<div id="test2"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<!--引入prop-types,用于对组件标签属性进行限制-->
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
class Person extends React.Component {
render() {
//props是只读的,不可进行修改
const {name,age,sex} = this.props
return (
<div>
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
</div>
);
}
}
//对标签属性进行类型,必要性限制
Person.protoType = {
name: PropTypes.string.isRequired, // 限制name必传且类型为string
age: PropTypes.number,
sex: PropTypes.string,
speak: PropTypes.func
}
//指定默认标签属性值
Person.defaultProps = {
sex: "男",
age: 18
}
function speak() {
return "哈哈哈哈"
}
//2.渲染组件到页面
const p = {name:"张三", age:66, sex:'男'}
ReactDOM.render(<Person name="tom" age={19} sex="男" speak={speak}/>,document.getElementById('test'))
ReactDOM.render(<Person name="jim" age="10" sex="男"/>,document.getElementById('test1'))
//语法糖
ReactDOM.render(<Person {...p}/>,document.getElementById('test2'))
</script>
</body>
</html>
简写
代码语言:javascript复制<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<div id="test1"></div>
<div id="test2"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<!--引入prop-types,用于对组件标签属性进行限制-->
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
class Person extends React.Component {
// constructor(props) {
// //构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
// super(props);
// }
//对标签属性进行类型,必要性限制
static protoType = {
name: PropTypes.string.isRequired, // 限制name必传且类型为string
age: PropTypes.number,
sex: PropTypes.string
}
//指定默认标签属性值
static defaultProps = {
sex: "男",
age: 18
}
render() {
//props是只读的,不可进行修改
const {name,age,sex} = this.props
return (
<div>
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
</div>
);
}
}
ReactDOM.render(<Person name="tom" />,document.getElementById('test'))
</script>
</body>
</html>
函数式组件使用props
代码语言:javascript复制<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<div id="test1"></div>
<div id="test2"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<!--引入prop-types,用于对组件标签属性进行限制-->
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
function Person(props) {
const {name, age, sex} = props
return (
<div>
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
</div>
) ;
}
//对标签属性进行类型,必要性限制
Person.protoType = {
name: PropTypes.string.isRequired, // 限制name必传且类型为string
age: PropTypes.number,
sex: PropTypes.string
}
//指定默认标签属性值
Person.defaultProps = {
sex: "男",
age: 18
}
ReactDOM.render(<Person name="tom" sex="女" age={18}/>,document.getElementById('test'))
</script>
</body>
</html>
注意点
代码语言:javascript复制1. 通过标签属性从组件外向组件内传递变化的数据
2. 注意: 组件内部不要修改props数据
3. 内部通过this.props.xx读取某个属性值
4. props中的属性值进行类型限制和必要性限制
4.1 React v15.5 开始已弃用
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number
}
4.2 使用prop-types库进限制(需要引入prop-types库)
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.
}
5. 扩展属性: 将对象的所有属性通过props传递
<Person {...person}/>
6. 默认属性值
Person.defaultProps = {
age: 18,
sex:'男'
}
ref
- 点击按钮, 提示第一个输入框中的值
- 当第2个输入框失去焦点时, 提示这个输入框中的值
理解
组件内的标签可以定义ref属性来标识自己
字符串类型ref
代码语言:javascript复制<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
class Demo extends React.Component {
//左侧
showData = () => {
const { input1 } = this.refs
alert(input1.value)
}
//右侧
showData2 = () => {
const { input2 } = this.refs
alert(input2.value)
}
render() {
return (
<div>
<input ref="input1" type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧数据</button>
<br/>
<hr/>
<input onBlur={this.showData2} ref="input2" type="text" placeholder="失去焦点提示数据"/>
</div>
);
}
}
ReactDOM.render(<Demo/>, document.getElementById("test"))
/**
* string类型的ref是过时的API
* https://react.docschina.org/docs/refs-and-the-dom.html#legacy-api-string-refs
*
* https://github.com/facebook/react/pull/8333#issuecomment-271648615
*/
</script>
</body>
</html>
回调函数类型ref
代码语言:javascript复制<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
class Demo extends React.Component {
//左侧
showData = () => {
const {input1} = this
alert(input1.value)
}
//右侧
showData2 = () => {
const {input2} = this
alert(input2.value)
}
render() {
return (
<div>
<input ref={currentNode => this.input1 = currentNode} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧数据</button>
<br/>
<hr/>
<input ref={currentNode => this.input2 = currentNode} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test"))
</script>
</body>
</html>
代码语言:javascript复制如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
class Demo extends React.Component {
state = {isHot:true}
changeWeather = () => {
const {isHot} = this.state
this.setState({isHot:!isHot})
}
//左侧
showData = () => {
const {input1} = this
alert(input1.value)
}
saveInput = (c) => {
this.input1 = c;
console.log('@',c);
}
render() {
const {isHot} = this.state
return (
<div>
<h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2>
<button onClick={this.changeWeather}>点击切换天气</button>
{/*<input ref={(currentNode) => { this.input1 = currentNode; console.log('@',currentNode);} } type="text" placeholder="点击按钮提示数据"/> */}
<input ref={this.saveInput} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧数据</button>
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test"))
</script>
</body>
</html>
createRef
代码语言:javascript复制<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
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"))
</script>
</body>
</html>
注意点
代码语言:javascript复制1. string类型的ref是过时的API,可能会在未来版本被移除,建议使用回调函数或createRef API来代替。
<input ref="input1"/>
2. 回调函数类型的ref
<input ref={(c)=>{this.input1 = c}} />
2.1 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素
<input ref={this.saveInput} /> //通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题
3. createRef创建ref容器
myRef = React.createRef()
<input ref={this.myRef}/>
事件处理
代码语言:javascript复制1.通过onXxx属性指定事件处理函数(注意大小写)
1) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件___兼容性
2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)___高效性
2.通过event.target得到发生事件的DOM元素对象___不要过度使用ref
代码语言:javascript复制<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">/*一定要以text/babel来声明*/
class Demo extends React.Component {
/**
1. 通过onXxx属性指定事件处理函数(注意大小写)
1) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件___兼容性
2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)___高效性
2. 通过event.target得到发生事件的DOM元素对象___不要过度使用ref
*
*/
// 创建ref容器
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 onBlur={this.showData2} type="text" placeholder="=失去焦点显示数据"/>
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test"))
</script>
</body>
</html>