最近开始接触react,本文是自己学习过程中做的一点学习笔记,如有错误欢迎指出哈哈哈
1、hello React
babel.js 的作用
(1) 浏览器不能直接解析 JSX 代码, 需要 babel 转译为纯 JS 的代码才能运行
(2) 只要用了 JSX,都要加上 type=“text/babel”, 声明需要 babel 来处理
<!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>
<!-- react核心库 -->
<script src="../../js//react.development.js"></script>
<!-- 用于支持react支持dom操作 -->
<script src="../../js//react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转换成js -->
<script src="../../js/babel.min.js"></script>
<script type="text/babel">
// 创建虚拟dom
const VDOM=<h1>Hello,React</h1>
// 渲染虚拟dom到页面
ReactDOM.render(VDOM,document.getElementById('test'));
</script>
</body>
</html>
2、创建虚拟dom的两种方式
- 纯 JS 方式(一般不用),如果标签太多,会嵌套太多层
- JSX 方式
//纯js方式
<!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>
<!-- react核心库 -->
<script src="../../js//react.development.js"></script>
<!-- 用于支持react支持dom操作 -->
<script src="../../js//react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转换成js -->
<script src="../../js/babel.min.js"></script>
<script type="text/javascript">
// 创建虚拟dom
// const VDOM=React.createElement(标签名,标签属性,标签内容)
const VDOM=React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello,React'));
// 渲染虚拟dom到页面
ReactDOM.render(VDOM,document.getElementById('test'));
</script>
</body>
</html>
//JSX方式
<!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>
<!-- react核心库 -->
<script src="../../js//react.development.js"></script>
<!-- 用于支持react支持dom操作 -->
<script src="../../js//react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转换成js -->
<script src="../../js/babel.min.js"></script>
<script type="text/babel">
// 创建虚拟dom
const VDOM=(
<h1 id="title">
<span>Hello,React</span>
</h1>
)
// 渲染虚拟dom到页面
ReactDOM.render(VDOM,document.getElementById('test'));
</script>
</body>
</html>
React 提供了一些 API 来创建一种 “特别” 的一般 js 对象
const VDOM = React.createElement('xx',{id:'xx'},'xx')
上面创建的就是一个简单的虚拟 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>Document</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="test"></div>
<div id="demo"></div>
<!-- react核心库 -->
<script src="../../js//react.development.js"></script>
<!-- 用于支持react支持dom操作 -->
<script src="../../js//react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转换成js -->
<script src="../../js/babel.min.js"></script>
<script type="text/babel">
// 创建虚拟dom
const VDOM=(
<h1 id="title">
<span>Hello,React</span>
</h1>
)
// 渲染虚拟dom到页面
ReactDOM.render(VDOM,document.getElementById('test'));
console.log(VDOM);
console.log(typeof VDOM);
console.log(document.getElementById('demo'));
</script>
</body>
</html>
- 虚拟 DOM 对象最终都会被 React 转换为真实的 DOM
- 我们编码时基本只需要操作 react 的虚拟 DOM 相关数据, react 会转换为真实
DOM 变化而更新界。
3、jsx语法规则:
全称: JavaScript XML
- react 定义的一种类似于 XML 的 JS 扩展语法: JS + XML 本质是
React.createElement(component, props, …children)方法的语法糖 - 作用: 用来简化创建虚拟 DOM
- 写法:
var ele = <h1>Hello JSX!</h1>
- 它不是字符串, 也不是 HTML/XML 标签
- 它最终产生的就是一个 JS 对象
1.定义虚拟DOM时,不要写引号。
2.标签中混入__JS表达式__时要用{}。
3.样式的类名指定不要用class,要用className。
4.内联样式,要用style={{key:value}}的形式去写。
5.只有一个根标签
6.标签必须闭合
7.标签首字母
(1).若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错。
(2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
<style>
.title{
background-color: orange;
width: 200px;
}
</style>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
const myId="demo";
const myData="Hello,React";
const VDOM=(
<div>
<h2 className="title" id={myId.toLowerCase()}>
{myData}
</h2>
<span className="title" id={myId.toUpperCase()} style={{backgroundColor:"blue",fontSize:"26px"}}>{myData}</span>
<input type="text"/>
</div>
)
ReactDOM.render(VDOM,document.getElementById('test'));
</script>
</body>
</html>
练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jsx小练习</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" >
//模拟一些数据
const data = ['Angular','React','Vue']
//1.创建虚拟DOM
const VDOM = (
<div>
<h1>前端js框架列表</h1>
<ul>
{
data.map((item,index)=>{
return <li key={index}>{item}</li>
})
}
</ul>
</div>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
一定注意区分:【js语句(代码)】与【js表达式】
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
下面这些都是表达式:(可以用const a=…表达)
(1). a
(2). a+b
(3). demo(1)
(4). arr.map()
(5). function test () {}
2.语句(代码):
下面这些都是语句(代码):
(1).if(){}
(2).for(){}
(3).switch(){case:xxxx}
4、模块与组件、模块化与组件化
4.1、模块
- 理解:向外提供特定功能的 js 程序, 一般就是一个 js 文件
- 为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。
- 作用:复用 js, 简化 js 的编写, 提高 js 运行效率
4.2、组件
- 理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image 等等)
- 为什么要用组件: 一个界面的功能更复杂
- 作用:复用编码, 简化项目编码, 提高运行效率
4.3、模块化
当应用的 js 都以模块来编写的, 这个应用就是一个模块化的应用
4.4、组件化
当应用是以多组件的方式实现, 这个应用就是一个组件化的应用
5、组件
5.1、函数式组件
1.React解析组件标签,找到了函数式组件。
2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
3.组件名和标签必须大写,函数必须要有返回值
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建函数式组件
function Demo(){
console.log(this);
return <h2> 我是用函数定义的组件(适用于简单组件的定义)</h2>
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
</script>
</body>
</html>
5.2、类式组件
执行了ReactDOM.render(<MyComponent/>,.......)
之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟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>Document</title>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
render(){
return <h2>我是用类定义的组件(适用于复杂组件的定义) </h2>
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
</script>
</body>
</html>
6、组件实例的三大属性state
6.1、state中this指向
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
//初始化状态
this.state={
isHot:true
}
}
render(){
const {isHot}=this.state;
return <h2>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
}
ReactDOM.render(<Demo/>,(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>Document</title>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
isHot:true
}
}
render(){
const {isHot}=this.state;
return <h2 onClick={changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
function changeWeather(){
console.log("标题被点击了");
}
</script>
</body>
</html>
如果是
render(){
const {isHot}=this.state;
return <h2 onClick={demo()}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
将会调用demo函数,没有点击控制台也会输出,undifined作为onClick的回调了
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
isHot:true
}
}
//render是放在哪里的?—— Demo的原型对象上,供实例使用。
//render中的this是谁?—— Demo的实例对象 <=> Demo组件实例对象。
render(){
const {isHot}=this.state;
return <h2 onClick={changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
function changeWeather(){
console.log(this);
console.log("标题被点击了");
}
</script>
</body>
</html>
babel在翻译的时候,禁止自定义函数指向window,所以changeWeather方法里触碰不到组件实例对象,不能读取
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
isHot:true
}
}
render(){
const {isHot}=this.state;
return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
changeWeather()
{
console.log(this);
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
</script>
</body>
</html>
changWeather已经放在类中了,是类中的方法了,render也是类中的方法,但是render中的this指向没有问题,因为执行了ReactDOM.render(<组件名/>…)之后,React解析组件标签,找到了组件。发现组件是使用类定义的,随后new出来该类的实例,并__通过该实例调用到原型上的render方法__。将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
所以render方法有被组件实例调用。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<script type="text/javascript" >
class Person {
constructor(name,age){
this.name = name
this.age = age
}
study(){
//study方法放在了哪里?——类的原型对象上,供实例使用
//通过Person实例调用study时,study中的this就是Person实例
console.log(this);
}
}
const p1 = new Person('tom',18)
p1.study() //通过实例调用study方法
const x = p1.study
x()
</script>
</body>
</html>
相当于x是study方法的另一个引用,x()相当于直接调用,如果是直接调用,this会指向window,但是类中自定义方法都__局部开启了严格模式__,所以调用后this指向是undifine
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
isHot:true
}
}
render(){
const {isHot}=this.state;
return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
changeWeather()
{
console.log(this);
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
</script>
</body>
</html>
所以这里面<h2 onClick={this.changeWeather}>
相当于直接找到了changeWeather方法把它交给了onClick,一点击就直接调用这个方法了,不是实例对象调用的
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
isHot:true
}
}
render(){
const {isHot}=this.state;
return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
changeWeather()
{
console.log(this);
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
const d=new Demo();
d.changeWeather();
</script>
</body>
</html>
模拟实例对象调用,谁调用指向谁,所以this指向实例对象
总的来说,就是
- changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
- 由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
- 类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
6.2、this指向解决
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
isHot:true
}
this.changeWeather=this.changeWeather.bind(this);
}
render(){
const {isHot}=this.state;
return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
changeWeather()
{
console.log(this);
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
</script>
</body>
</html>
构造器中的this就是指向实例对象。
this.changeWeather=this.changeWeather.bind(this);
- 第一个this指向实例对象,第二个this也指向实例对象。
- 看右边式子,虽然实例对象中没有changeWeather这个方法,但是会顺着原型链去找,然后就找到了方法,bind()会生产一个函数,同时根据传递的第一个参数改变this指向,第三个当前也是指向实例对象的,所以生产一个新的函数的this指向改成指向构造器。
- 然后你有了一个指向实例对象的函数了。把这个函数放在了这个实例对象自身,并且把它命名为changeWeather
bind 没有规定,传递值和数组都可以。call 和 apply 函数的执行是直接执行的,而 bind 函数会__返回一个函数__,然后我们想要调用的时候才会执行。
然后点击后,触发的是实例对象上的changeWeather了,而不是顺着原型链找到的changeWeather了
改下名字,测试一下
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
isHot:true
}
this.tool=this.changeWeather.bind(this);
}
render(){
const {isHot}=this.state;
return <h2 onClick={this.tool}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
changeWeather()
{
console.log(this);
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
</script>
</body>
</html>
6.3、setState的使用
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
isHot:true
}
this.tool=this.changeWeather.bind(this);
}
render(){
const {isHot}=this.state;
return <h2 onClick={this.tool}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
changeWeather()
{
this.state.isHot=!this.state.isHot
console.log(this.state.isHot)
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
</script>
</body>
</html>
多次点击,页面没有变化,但是控制台会有输出
改了但是没完全改,react不认可
状态不可直接更改,要借助一个内置的api
这是直接更改,是错误的
this.state.isHot=!this.state.isHot
调用setState
<!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>
<script src="../../js//react.development.js"></script>
<script src="../../js//react-dom.development.js"></script>
<script src="../../js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
// 创建类式定义组件
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
isHot:true
}
this.tool=this.changeWeather.bind(this);
}
render(){
const {isHot}=this.state;
return <h2 onClick={this.tool}>今天天气很{isHot?'炎热':'凉爽'}</h2>
}
changeWeather()
{
const isHot=this.state.isHot;
console.log(this);
this.setState({isHot:!isHot})
console.log(this.state.isHot);
}
}
ReactDOM.render(<Demo/>,(document.getElementById('test')));
</script>
</body>
</html>
状态必须通过setState进行更新,且更新是一种合并,不是替换。其他状态值不会受到影响
6.4、简写state
类中可以直接写赋值语句,含义是给类的实例对象添加一个属性
class Car {
constructor(name,price){
this.name = name
this.price = price
// this.wheel = 4
}
//类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1
a = 1
wheel = 4
static demo = 100
}
const c1 = new Car('奔驰c63',199)
console.log(c1);
console.log(Car.demo);
给__组件的实例对象__添加一个箭头函数,由于箭头函数中没有this,将从上下文寻找this,此时箭头函数中this指向实例对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</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">
//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'))
</script>
</body>
</html>
6.5、总结
- 组件中 render 方法中的 this 为组件实例对象
- 组件自定义的方法中 this 为 undefined,如何解决?
a) 强制绑定 this: 通过函数对象的 bind()
b) 箭头函数 - 状态数据,不能直接修改或更新
7、组件实例的三大属性props
7.1、基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</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-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">
//1.创建组件
class Weather extends React.Component{
render(){
console.log(this);
return(
<ul>
<li>{this.props.name}</li>
<li>{this.props.age}</li>
</ul>
)
}
}
ReactDOM.render(<Weather name="tom" age="19"/>,document.getElementById('test1'))
ReactDOM.render(<Weather name="jack"age="18"/>,document.getElementById('test2'))
ReactDOM.render(<Weather name="mike"age="17"/>,document.getElementById('test3'))
</script>
</body>
</html>
7.2、批量传递props
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</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-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">
//1.创建组件
class Weather extends React.Component{
render(){
const {name,age}=this.props;
console.log(this);
return(
<ul>
<li>{name}</li>
<li>{age}</li>
</ul>
)
}
}
const p={
name:'jack',
age:19
}
// ReactDOM.render(<Weather name={p.name}age={p.age}/>,document.getElementById('test1'))
ReactDOM.render(<Weather {...p}/>,document.getElementById('test1'))
</script>
</body>
</html>
7.3、对props进行限制
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</title>
</head>
<body>
<div id="test1"></div>
<script type="text/javascript" src="../../js/react.development.js"></script>
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<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">
//1.创建组件
class Person extends React.Component{
render(){
const {name,age,sex,speak}=this.props;
console.log(this);
return(
<ul>
<li>{name}</li>
<li>{age}</li>
<li>{sex}</li>
</ul>
)
}
}
Person.propTypes={
name:PropTypes.string.isRequired,//限制name为字符串且必传
age:PropTypes.number,//限制age为number类型
speak:PropTypes.func//限制speak为函数类型,为了避免和原生js中的关键字function冲突,所以是func
}
Person.defaultProps={
sex:'男',//sex默认值为男
age:18//age默认值为18
}
ReactDOM.render(<Person name="jack" age={19} speak='1'/>,document.getElementById('test1'))
function speak()
{
console.log("你好哇");
}
</script>
</body>
</html>
7.4、props简写
props只能读不能改
类中可以直接写赋值语句,含义是给类的实例对象添加一个属性
class Car {
constructor(name,price){
this.name = name
this.price = price
// this.wheel = 4
}
//类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1
a = 1
wheel = 4
static demo = 100//相当于在类的外面写Car.demo=100
}
const c1 = new Car('奔驰c63',199)
console.log(c1);
console.log(Car.demo);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</title>
</head>
<body>
<div id="test1"></div>
<script type="text/javascript" src="../../js/react.development.js"></script>
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<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">
//1.创建组件
class Person extends React.Component{
static propTypes={
name:PropTypes.string.isRequired,//限制name为字符串且必传
age:PropTypes.number,//限制age为number类型
speak:PropTypes.func//限制speak为函数类型,为了避免和原生js中的关键字function冲突,所以是func
}
static defaultProps={
sex:'男',//sex默认值为男
age:18//age默认值为18
}
render(){
const {name,age,sex,speak}=this.props;
console.log(this);
return(
<ul>
<li>{name}</li>
<li>{age}</li>
<li>{sex}</li>
</ul>
)
}
}
ReactDOM.render(<Person name="jack" age={19} speak='1'/>,document.getElementById('test1'))
function speak()
{
console.log("你好哇");
}
</script>
</body>
</html>
7.5、props与构造器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对props进行限制</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-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">
//创建组件
class Person extends React.Component{
constructor(props){
//构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
// console.log(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(){
// console.log(this);
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'))
</script>
</body>
</html>
7.6、函数式组件使用props
函数式组件里面没有实例对象,三大属性按道理都不能使用,但是可以使用props,但是函数可以接受参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对props进行限制</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
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'))
</script>
</body>
</html>
8、refs属性
组件内的标签可以定义 ref 属性来标识自己
8.1、字符串形式ref
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</title>
</head>
<body>
<div id="test1"></div>
<script type="text/javascript" src="../../js/react.development.js"></script>
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<script type="text/javascript" src="../../js/babel.min.js"></script>
<script type="text/javascript" src="../../js/prop-types.js"></script>
<script type="text/babel">
class Demo extends React.Component
{
showData=()=>{
console.log(this);
console.log(this.refs.input1);
console.log(this.refs.input1.value);
}
showData2=()=>{
console.log(this.refs.input2.value);
}
render()
{
return(
<div>
<input ref="input1" type="text"/>
<button onClick={this.showData}>点击显示内容</button>
<input ref='input2' onBlur={this.showData2} type="text"/>
</div>
)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test1'));
</script>
</body>
</html>
8.2、回调形式的ref
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</title>
</head>
<body>
<div id="test1"></div>
<script type="text/javascript" src="../../js/react.development.js"></script>
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<script type="text/javascript" src="../../js/babel.min.js"></script>
<script type="text/javascript" src="../../js/prop-types.js"></script>
<script type="text/babel">
class Demo extends React.Component
{
showData=()=>{
console.log(this.input1.value);
}
showData2=()=>{
console.log(this.input2.value);
}
render()
{
return(
<div>
<input ref={(node)=>{console.log(node);this.input1=node;console.log(this)}} type="text"/>
<button onClick={this.showData}>点击显示内容</button>
<input ref={(node)=>{console.log(node);this.input2=node,console.log(this)}} onBlur={this.showData2} type="text"/>
</div>
)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test1'));
</script>
</body>
</html>
实例对象调用render方法,由于箭头函数没有指定的this,向外面找,于是指向实例对象this.input1=node,给实例对象添加了一个属性
8.3、refs调用次数
如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</title>
</head>
<body>
<div id="test1"></div>
<script type="text/javascript" src="../../js/react.development.js"></script>
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<script type="text/javascript" src="../../js/babel.min.js"></script>
<script type="text/javascript" src="../../js/prop-types.js"></script>
<script type="text/babel">
class Demo extends React.Component
{
state={isHot:true}
showData=()=>{
console.log(this.input1.value);
}
showData2=()=>{
console.log(this.input2.value);
}
change=()=>{
let {isHot}=this.state;
this.setState({isHot:!isHot})
}
render()
{
return(
<div>
<h1>今天天气很{this.state.isHot?'炎热':'凉爽'}</h1>
<button onClick={this.change}>点击切换</button>
<input ref={(node)=>{console.log(node);}} type="text"/>
<button onClick={this.showData}>点击显示内容</button>
</div>
)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test1'));
</script>
</body>
</html>
ref 的回调函数定义成 class 的绑定函数的方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</title>
</head>
<body>
<div id="test1"></div>
<script type="text/javascript" src="../../js/react.development.js"></script>
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<script type="text/javascript" src="../../js/babel.min.js"></script>
<script type="text/javascript" src="../../js/prop-types.js"></script>
<script type="text/babel">
class Demo extends React.Component
{
state={isHot:true}
showData=()=>{
console.log(this.input1.value);
}
showData2=()=>{
console.log(this.input2.value);
}
change=()=>{
let {isHot}=this.state;
this.setState({isHot:!isHot})
}
showNode=(node)=>{
console.log(node);
this.input1=node;
}
render()
{
return(
<div>
<h1>今天天气很{this.state.isHot?'炎热':'凉爽'}</h1>
<button onClick={this.change}>点击切换</button>
<input ref={this.showNode} type="text"/>
<button onClick={this.showData}>点击显示内容</button>
</div>
)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test1'));
</script>
</body>
</html>
8.4、createRef
React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>state简写方式</title>
</head>
<body>
<div id="test1"></div>
<script type="text/javascript" src="../../js/react.development.js"></script>
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<script type="text/javascript" src="../../js/babel.min.js"></script>
<script type="text/javascript" src="../../js/prop-types.js"></script>
<script type="text/babel">
class Demo extends React.Component
{
myref=React.createRef();
myref2=React.createRef();
showData=()=>{
console.log(this.myref.current.value);
}
showData2=()=>{
console.log(this.myref2.current.value);
}
render()
{
return(
<div>
<input ref={this.myref} type="text"/>
<button onClick={this.showData}>点击显示内容</button>
<input ref={this.myref2} onBlur={this.showData2} type="text"/>
</div>
)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test1'));
</script>
</body>
</html>
9、事件处理
- 通过 onXxx 属性指定事件处理函数(注意大小写)
React 使用的是自定义(合成)事件, 而不是使用的原生 DOM 事件,为了更好的兼容性
React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素),为了的高效 - 通过 event.target 得到发生事件的 DOM 元素对象,不要过度使用ref
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="test1"></div>
<script type="text/javascript" src="../../js/react.development.js"></script>
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<script type="text/javascript" src="../../js/babel.min.js"></script>
<script type="text/javascript" src="../../js/prop-types.js"></script>
<script type="text/babel">
class Demo extends React.Component
{
myref=React.createRef();
myref2=React.createRef();
showData=()=>{
console.log(this.myref.current.value);
}
showData2=(event)=>{
console.log(event.target);
}
render()
{
return(
<div>
<input ref={this.myref} type="text"/>
<button onClick={this.showData}>点击显示内容</button>
<input ref={this.myref2} onBlur={this.showData2} type="text"/>
</div>
)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test1'));
</script>
</body>
</html>
点击第二个输入框输入,然后失去焦点