目录
一、为什么我来安利你学习 React?
二、使用 React 的前置工作
三、简易 demo 学开发
3.1、jsx语法
3.2、函数式组件 demo
3.3、简单类组件定义
3.4、复杂类组件定义
3.4.1、state
写法一:复杂式
写法二:简便式
3.4.2、props
类型限制
props简写
函数式组件props
3.4.3、refs
ref 回调函数
createRef
一、为什么我来安利你学习 React?
效率起飞!!!
以往我们都是通过原生的 js 直接去操作真实 DOM ,而真实的 DOM 相对于虚拟 DOM 更加重量,一旦对真实 DOM 的操作频繁,带来的开销是不可估量的,而 React 却是通过构建虚拟 DOM,再转化为真是 DOM 来呈现在浏览器上,无需真实 DOM 附带繁杂的属性~
二、使用 React 的前置工作
一定要注意,按照以下顺序引入到你的项目中!
1.引入 react 核心库 react.development.js
下载地址:https://unpkg.com/react@18.0.0/umd/react.development.js
2.React 渲染组件 react-dom.developmengt.js
下载地址:https://unpkg.com/react-dom@18.0.0/umd/react-dom.development.js
3.引入 babel 用于将 jsx 转为 js babel.min.js
下载地址:https://unpkg.com/babel-standalone@6/babel.min.js
三、简易 demo 学开发
3.1、jsx语法
我们在 <script type="text/babel"><script/>中编写需要注意一下几点
- 定义虚拟 DOM 时,不要写引号。
- 标签中混入 JS 表达式时需要使用 {}。
- 样式的类名指定不要用 class ,要用 className。
- 内联样式,要用 style={{key:value}} 的形式去写。
- 只能有一个根标签。
- 标签首字母:(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>
</head>
<style>
.title{
background-color: aqua;
}
</style>
<body>
<!-- 准备一个容器 -->
<div id="test"></div>
<!-- 1.引入 react 核心库 -->
<script type="text/javascript" src="../model/react.development.js"></script>
<!-- 2.渲染组件到页面 -->
<script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
<!-- 3.引入 babel 用于将 jsx 转为 js -->
<script type="text/javascript" src="../model/babel.min.js"></script>
<script type="text/babel">
//模拟数据
const data = ['Angular', 'React', 'Vue'];
const myId = 'tITLe';
const myData = 'hello react';
//1.构造虚拟 DOM
const VDOM = (
<div>
<h1>前端 js 框架列表</h1>
<ul>
{
data.map((str, index)=>{
return <li key={index}>{str}</li>
})
}
</ul>
<div>
<h1 className="title" id={myId.toLowerCase()}>
<span style={{color:'white', fontSize:'29px'}}>
{myData.toLocaleLowerCase()}
</span>
</h1>
<h1 className="title" id={myId.toUpperCase()}>
<span style={{color:'white', fontSize:'29px'}}>
{myData.toLocaleLowerCase()}
</span>
</h1>
<input type="text"/>
</div>
</div>
);
//2.渲染到浏览器
ReactDOM.render(VDOM, document.querySelector("#test"));
</script>
</body>
</html>
执行结果如下
3.2、函数式组件 demo
<!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>
<!-- 1.引入 react 核心库 -->
<script type="text/javascript" src="../model/react.development.js"></script>
<!-- 2.渲染组件到页面 -->
<script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
<!-- 3.引入 babel 用于将 jsx 转为 js -->
<script type="text/javascript" src="../model/babel.min.js"></script>
<script type="text/babel">
function MyComponent() {
return "这是一个 Demo 组件(首字母必须大写,才可以被 render 追踪为组件)";
}
ReactDOM.render(<MyComponent/>, document.querySelector("#test"));
</script>
</body>
</html>
问题:执行了 ReactDOM,render(<Demo/>, document.querySelector("#test")) 之后,发生了什么?
1. React 解析组件标签,找到了 MyComponent 组件。
2. 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟 DOM 转为真是的 DOM ,随后呈现在主页面中。
3.3、简单类组件定义
类组件通过继承 React.Component ,重写 render 方法来渲染页面
<!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>
<!-- 1.引入 react 核心库 -->
<script type="text/javascript" src="../model/react.development.js"></script>
<!-- 2.渲染组件到页面 -->
<script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
<!-- 3.引入 babel 用于将 jsx 转为 js -->
<script type="text/javascript" src="../model/babel.min.js"></script>
<script type="text/babel">
//创建类式组件(必须继承 React.Component,重写 render 方法)
class MyComponent extends React.Component {
render() {
//render 中的 this 是 MyComponent 的实例对象
return <h2>我是用类定义的组件(适用于复杂组件的定义)</h2>
}
}
ReactDOM.render(<MyComponent/>, document.querySelector("#test"));
/*
执行了 ReactDOM,render(<MyComponent/>, document.querySelector("#test")) 之后,发生了什么?
1. React 解析组件标签,找到了 MyComponent 组件。
2. 发现组件是使用类定义的,随后 new 出来该类的实例,并通过该实例调用到原型上的 render 方法
3.将 render 返回的虚拟 DOM 转为真实的 DOM ,随后呈现在页面中
*/
</script>
</body>
</html>
3.4、复杂类组件定义
3.4.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>Document</title>
</head>
<body>
<!-- 准备一个容器 -->
<div id="test"></div>
<!-- 1.引入 react 核心库 -->
<script type="text/javascript" src="../model/react.development.js"></script>
<!-- 2.渲染组件到页面 -->
<script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
<!-- 3.引入 babel 用于将 jsx 转为 js -->
<script type="text/javascript" src="../model/babel.min.js"></script>
<script type="text/babel">
//创建组件
class MyComponent extends React.Component{
constructor(props) {
super(props); //先别管为什么,这个必须有
this.state = {isHot: true} //这里必须是一个对象
//解决 changeWeather 中 this 指向问题
this.nick = this.changeWeather.bind(this);
}
render() {
return <h2 onClick={this.nick}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}!</h2>
}
//作为事件进行回调
changeWeather() {
//注意:状态不可以直接更改,需要使用内置 API 去更改
//this.state.isHot = !isHot //这是错误写法
//获取原来的 isHot 值
const isHot = this.state.isHot;
//注意:状态 state 必须通过 setState 更改,并且这里不是覆盖,而是合并
this.setState({isHot: !isHot});
}
}
//渲染
ReactDOM.render(<MyComponent/>, document.querySelector("#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>
</head>
<body>
<!-- 准备一个容器 -->
<div id="test"></div>
<!-- 1.引入 react 核心库 -->
<script type="text/javascript" src="../model/react.development.js"></script>
<!-- 2.渲染组件到页面 -->
<script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
<!-- 3.引入 babel 用于将 jsx 转为 js -->
<script type="text/javascript" src="../model/babel.min.js"></script>
<script type="text/babel">
//创建组件
class MyComponent extends React.Component{
//初始化状态
state = {isHot: true}
render() {
return <h2 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}!</h2>
}
//自定义方法
//箭头函数的 this 就是外层的类(解决 this 指向问题)
changeWeather = () => {
const isHot = this.state.isHot;
this.setState({isHot: !isHot});
}
}
//渲染
ReactDOM.render(<MyComponent/>, document.querySelector("#test"));
</script>
</body>
</html>
3.4.2、props
除了类构造器可以进行构造赋值传参, React 还提供了一种方式,就是 props 属性,通过使用 ReactDOM.sender 就可以直接传入参数
<!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="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!-- 1.引入 react 核心库 -->
<script type="text/javascript" src="../model/react.development.js"></script>
<!-- 2.渲染组件到页面 -->
<script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
<!-- 3.引入 babel 用于将 jsx 转为 js -->
<script type="text/javascript" src="../model/babel.min.js"></script>
<script type="text/babel">
//定义组件
class Person extends React.Component {
render() {
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" age="19" sex="男"/>, document.querySelector("#test1"));
ReactDOM.render(<Person name="jerry" age="17" sex="女"/>, document.querySelector("#test2"));
//更简单的渲染:
//模拟前端 ajax传入
const p = {name: "zhangsan", age: 10, sex: "男"}
ReactDOM.render(<Person {...p}/> , document.querySelector("#test3"));
//另外若需要修改并合并
ReactDOM.render(<Person {...p} name="lisi"/>, document.querySelector("#test3"));
</script>
</body>
</html>
类型限制
如果有需要,我们还可以对传入的标签属性进行类型限制或者是默认属性,首先,我们需要引入下面这个库
https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js
代码如下:
//定义组件
class Person extends React.Component {
render() {
const {name, age, sex} = this.props;
return (
<div>
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
</div>
);
}
}
//对标签属性进行类型必要性的限制
Person.propTypes = {
// 限制 name 属性必须为 string,isRequired 表示必须是必填项
name:PropTypes.string.isRequired,
// 限制 sex 属性必须为 string 类型
sex:PropTypes.string,
// 限制 age 属性必须为 number 属性
age:PropTypes.number,
// 限制 speak 属性必须为 函数
speak:PropTypes.func
}
//设置默认属性(如果没有参数传入)
Person.defaultProps = {
sex:"不男不女",
age:18
}
function speak() {
console.log("我要发言了~");
}
//渲染
ReactDOM.render(<Person speak={speak} name="tom" age="19" sex="男"/>, document.querySelector("#test1"));
props简写
直接给类添加propTypes
和defaultProps
属性,注意:是类属性,不是实例属性,所以加上static关键字
//定义组件
class Person extends React.Component {
constructor(props) {
/*
* 拓展
* 构造器是否接收props,并传递给super,取决于:是否希望在构造器中使用this访问props
* */
super(props);
console.log(this.props) // 通过实例使用props ,这里如果不传递props给super,this.props为undefind,可直接使用props,如下
console.log(props) //直接使用props
}
static propTypes = { //这里是类属性,不是实例
// 限制 name 属性必须为 string,isRequired 表示必须是必填项
name:PropTypes.string.isRequired,
// 限制 sex 属性必须为 string 类型
sex:PropTypes.string,
// 限制 age 属性必须为 number 属性
age:PropTypes.number,
// 限制 speak 属性必须为 函数
speak:PropTypes.func
}
static defaultProps = {
sex:"不男不女",
age:18
}
render() {
const {name, age, sex} = this.props;
return (
<div>
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
</div>
);
}
}
function speak() {
console.log("我要发言了~");
}
//渲染
ReactDOM.render(<Person speak={speak} name="tom" age="19" sex="男"/>, document.querySelector("#test1"));
函数式组件props
函数式组件不支持state和refs,但是也能使用props以及限制props限制.
function Person(props) {
const{name, age, sex} = props
return (
<div>
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
</div>
);
}
//对标签属性进行类型必要性的限制
Person.propTypes = {
// 限制 name 属性必须为 string,isRequired 表示必须是必填项
name:PropTypes.string.isRequired,
// 限制 sex 属性必须为 string 类型
sex:PropTypes.string,
// 限制 age 属性必须为 number 属性
age:PropTypes.number,
// 限制 speak 属性必须为 函数
speak:PropTypes.func
}
//设置默认属性(如果没有参数传入)
Person.defaultProps = {
sex:"不男不女",
age:18
}
function speak() {
console.log("我要发言了~");
}
//渲染
ReactDOM.render(<Person speak={speak} name="tom" age="19" sex="男"/>, document.querySelector("#test1"));
3.4.3、refs
在原生js中,通常使用document.getElementById、document.querySelector等这种类似的操作来获取我们需要的DOM元素
React为我们提供了一种非常特殊的属性 ref,你可以用来绑定到 render() 输出的任何组件上
下面是几个适合使用 refs 的情况:
- 管理焦点,文本选择或媒体播放。
- 触发强制动画。
- 集成第三方 DOM 库。
- 不能在函数组件上使用 ref 属性,因为他们没有实例
字符串形式的ref
给组件添加ref属性 ref="refName",然后就能通过在示例方法中通过this.refs.refName获得DOM
class Demo extends React.Component {
// 点击按钮时,显示左边输入框的数据
showInputData1 = () =>{
// 通过获取id的方式
// const input = document.getElementById('input1')
// alert(input.value)
// 通过ref
const { input1 } = this.refs
alert(input1.value)
}
// 右边输入框失去焦点时,显示右边输入框的数据
showInputData2 = () => {
const { input2 } = this.refs
alert(input2.value)
}
render() {
return (
<div>
<input ref="input1" id="input1" type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showInputData1}>点击提示左边的数据</button>
<input onBlur={this.showInputData2} ref="input2" type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
Ps:字符串形式的ref虽然方便,但是效率并不高,所以官方不建议使用,并可能会在未来的版本被移除
ref 回调函数
React 还支持另一种设置 refs 的方式,称为“回调 refs”。它能助你更精细地控制何时 refs 被设置和解除。
内联函数语法:ref={ currentNode => this.input1 = currentNode } —— 把ref当前所处的节点挂载在实例自身上,并取名为input1
回调函数语法:ref={ this.input2 } —— 把当前节点传递给回调函数input2
class Demo extends React.Component {
// 点击按钮时,显示左边输入框的数据
showInputData1 = () =>{
// 通过ref
const { input1 } = this
alert(input1.value)
}
// 右边输入框失去焦点时,显示右边输入框的数据
showInputData2 = () => {
alert(this.input2.value)
}
saveInput = (currentNode) => {
this.input2 = currentNode
}
/*
* ref={ currentNode => this.input1 = currentNode }
* 把ref当前所处的节点挂载在实例自身上,并取名为input1
* */
render() {
return (
<div>
<input ref={ currentNode => this.input1 = currentNode }/*内联函数*/ id="input1" type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showInputData1}>点击提示左边的数据</button>
<input onBlur={this.showInputData2} ref={ this.saveInput /*使用类绑定的函数作为回调函数*/} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
createRef
使用 React.createRef() 创建ref,并通过 ref 属性附加到 React 元素
React.createRef调用后会返回一个容器,该容器可以存储被ref所标识的节点
render执行的时候,发现有一个ref,而且是用createRef创建的容器,就会将当前ref所在的节点存储到这个容器里面
class Demo extends React.Component {
myRef = React.createRef(); // 一个节点单独使用一个
showInputData = () =>{
const { current } = this.myRef;
alert(current.value)
}
render() {
return (
<div>
<input ref={ this.myRef } id="input1" type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showInputData}>点击提示左边的数据</button>
</div>
)
}
}