1 基本理解与使用
函数式组件
<!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>1_函数式组件</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-from,用于支持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">
// 1. 创建函数式组件
function MyComponent() {
console.log(this); // 此处的this是undefined,因为babel编译后开启了严格模式
return <h2>我使用函数定义的组件(适用于【简单组件】的定义)</h2>;
}
// 2. 渲染组件到页面
ReactDOM.render(<MyComponent/>, document.getElementById('test'));
/*
执行了React.render(<MyComponent/>.......之后发生了什么)
1. react会解析组件标签,找到了Mycomponent组件。发现组件是使用函数定义的,随后调用该函数,将返回的虚拟Dom转为真实Dom,随后呈现在页面中
*/
</script>
</body>
</html>
类式组件
<!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>2_类式组件</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-from,用于支持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">
// 1.创建类式组件
class MyComponent extends React.Component{
render() {
// render方法放在了哪里? --- MyComponent的原型对象上,供实例使用
// render中的this是谁? --- MyComponent的实例对象 MyComponent组件的实例对象
console.log('render中的this', this);
return <h2>我使用类定义的组件(适用于【复杂组件】的定义)</h2>;
}
}
// 2.渲染组件到页面
ReactDOM.render(<MyComponent/>, document.getElementById('test'));
/*
执行了React.render(<MyComponent/>.......之后发生了什么)
1. react会解析组件标签,找到了Mycomponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法
3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中
*/
</script>
</body>
</html>
注意
-
组件名必须首字母大写
-
虚拟DOM元素只能有一个根元素
-
虚拟DOM元素必须有结束标签
类的复习
<!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>1_类的基本知识</title>
</head>
<body>
<script type="text/javascript">
/*
总结:
1.类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时,才写
2.如果A类继承了B类,且A类写了构造器,那么A类构造器中super是必须要调用的。
3.类中所定义的方法,都是放在了类的原型对象上,供实例使用
*/
// 创建一个Person类
class Person {
// 构造器方法
constructor(name, age) {
// 构造器中的this是谁?--类的实例对象
this.name = name;
this.age = age;
}
// 一般方法
speak() {
// speak方法放在了哪里? --- 类的原型对象上,供实例使用
// 通过Person实例调用speak时,speak中的this就是Person实例
console.log(`我叫${this.name},我年龄是${this.age}`);
}
}
// 创建一个student类,继承于Person类
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
// 重写从父类继承过来的方法
speak() {
console.log(`我叫${this.name},我年龄时${this.age},我读的是${this.grade}年级`);
}
study() {
// study方法放在了哪里? --- 类的原型对象上,供实例使用
// 通过Student实例调用study时,study中的this就是Student实例
console.log('我很努力的学习');
}
}
// 创建一个Person的实例对象
// const p1 = new Person('tom', 18);
// const p2 = new Person('jerry', 19);
// console.log(p1);
// console.log(p2);
// p1.speak();
// p2.speak();
// p1.speak.call({a: 1, b: 2});
const s1 = new Student('小张', 15, '高一');
console.log(s1);
s1.speak();
s1.study();
</script>
</body>
</html>
2 组件实例的三大核心属性1.state
<!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>state.html</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-from,用于支持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">
// 1.创建组件
class Weather extends React.Component {
constructor(props) {
super(props);
this.state = {isHot: true}
}
render() {
// 读取状态
const {isHot} = this.state;
return <h1 onClick={demo}>今天天气很{isHot ? '炎热' : '凉爽'}</h1>
}
}
// 2.渲染组件到页面
ReactDOM.render(<Weather/>, document.getElementById('test'));
function demo() {
alert('按钮3被点击了');
}
</script>
</body>
</html>
2.1 练习
需求:定义一个展示天气信息的组件
1. 默认展示天气炎热 或 凉爽
2. 点击文字切换天气
<!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>state.html</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-from,用于支持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">
// 1.创建组件
class Weather extends React.Component {
// 构造器调用几次?-----1次
constructor(props) {
super(props);
// 初始化状态
this.state = { isHot: true, wind: '微风' };
// 解决changeWeacther中this指向问题
this.changeWeather = this.changeWeather.bind(this);
}
// render调用几次?----- 点几次调用几次
render() {
// 读取状态
const { isHot, wind } = this.state;
return (
<h1 onClick={this.changeWeather}>今天天气很{isHot ? "炎热" : "凉爽"}, {wind}</h1>
);
}
// changeWeather调用几次?----- 点几次调用几次
changeWeather() {
// changeWeather方法放在了哪里? --- Weather的原型对象上,供实例使用
// 由于changeWeather是作为onClick的回调,所以不是通过实例调用,是直接调用
// 类中的方法默认开启了局部的严格模式,所以changeWeather中的this位undefined
// 获取原来的isHot值
const isHot = this.state.isHot;
// 严重注意:状态必须通过setState进行更新,更新是一种合并,不是替换
this.setState({isHot: !isHot})
// 严重注意:状态(state)不可以直接更改,下面这行就是直接更改
// this.state.isHit = !isHot; // 错误写法
}
}
// 2.渲染组件到页面
ReactDOM.render(<Weather />, document.getElementById("test"));
</script>
</body>
</html>
简写形式
<!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>state.html</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-from,用于支持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">
class Weather extends React.Component {
state = { isHot: true, 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})
}
}
ReactDOM.render(<Weather />, document.getElementById("test"));
</script>
</body>
</html>
2.2 理解
-
state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
-
组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
2.3 强烈注意
-
组件中render方法中的this为组件实例对象
-
组件自定义的方法中this为undefined,如何解决?
a) 强制绑定this: 通过函数对象的bind()
b) 箭头函数
-
状态数据,不能直接修改或更新
3 组件三大核心属性2: props
函数式组件能用props,但是不能用state,refs
3.1 效果
需求 自定义用来显示一个人员信息的组件
1. 姓名必须指定,且为字符串类型;
2. 性别为字符串类型,如果性别没有指定,默认为男
3. 年龄为字符串类型,且为数字类型,默认值为18
3.2 理解
-
每个组件对象都会有props(properties的简写)属性
-
组件标签的所有属性都保存在props中
3.3 作用
-
通过标签属性从组件外向组件内传递变化的数据
-
注意: 组件内部不要修改props数据
3.4 编码操作
-
内部读取某个属性值
this.props.name
-
对props中的属性值进行类型限制和必要性限制
第一种方式(React v15.5 开始已弃用):
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number
}
第二种方式(新):使用prop-types库进限制(需要引入prop-types库)
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number
}
- 扩展属性: 将对象的所有属性通过props传递
<Person {...person}/>
- 默认属性值:
Person.defaultProps = {
age: 18,
sex:'男'
}
-
组件类的构造函数
constructor(props){ super(props) console.log(props)//打印所有属性 }
eg:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello_react</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-from,用于支持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"> /* 此处一定要写babel */
// 创建组件
class Person extends React.Component {
state = {name: 'tom', age: 18, sex: '女'};
render() {
console.log(this);
const {name, age, sex} = this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
)
}
}
// 对标签属性进行类型、必要性限制
Person.propTypes = {
name: PropTypes.string.isRequired, // 限制name必传,且为字符串
sex: PropTypes.string, // 限制name为字符串
age: PropTypes.number, // 限制age为数值
speak: PropTypes.func, // 限制speak为函数
}
// 只当默认标签属性值
Person.defaultProps = {
sex: '不男不女', // sex默认值为男
age: 18 // sex默认值为男
}
// 渲染组件到页面
ReactDOM.render(<Person name="jerry" speak="1"/>, document.getElementById('test1'));
ReactDOM.render(<Person name="tom" age={18} sex="男"/>, document.getElementById('test2'));
const p = {name: '老刘', age: 18, sex: '女'};
console.log(...p);
// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>, document.getElementById('test3'));
ReactDOM.render(<Person {...p}/>, document.getElementById('test3'));
function speak() {
console.log('我说话了');
}
</script>
</body>
</html>
4 组件三大核心属性3: refs与事件处理
练习
需求: 自定义组件, 功能说明如下:
-
点击按钮, 提示第一个输入框中的值
-
当第2个输入框失去焦点时, 提示这个输入框中的值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>4_createRef</title> </head> <body> <!-- 准备好一个容器 --> <div id="test"></div> <!-- 引入react核心库 --> <script type="text/javascript" src="../js/react.development.js"></script> <!-- 引入react-from,用于支持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"> // 创建组件 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>
理解
组件内的标签可以定义ref属性来标识自己。
编码
- 字符串形式的ref
<input ref="input1"/>
- 回调形式的ref
<input ref={(c)=>{this.input1 = c}}
- createRef创建ref容器
myRef = React.createRef()
<input ref={this.myRef}/>
事件处理
-
通过onXxx属性指定事件处理函数(注意大小写)
-
React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 ---- 为了更好的兼容性
-
React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ----- 为了高效
-
-
通过event.target得到发生事件的DOM元素对象 ----- 不要过度使用ref