一、React概述
React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
详细教程可参见官网:
React 官方中文文档 – 用于构建用户界面的 JavaScript 库
React框架的书写方式分为两种,一种是脚本方式(JavaScript标签引入,练习使用);一种是react脚手架方式(常用)。
1.脚本方式创建react初始模板
为了能够正常使用react框架进行编程,我们创建好自己的项目之后,需要在页面中引入两个CDN链接:react库 和 react-dom库;
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
对于这两个远程地址也可直接在官网下载到本地之后直接用<script src=""></script>引入项目中;如下:
<script src="./react.development.js"></script> <script src="./react-dom.development.js"></script>
除此之外还应注意,React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。所以在React中使用的是JSX语法,但是浏览器不识别JSX,我们就需要引入babel(Babel 中文网 · Babel - 下一代 JavaScript 语法的编译器)来解析翻译,而且需要在script写上对应属性,格式如下:
//引入Babel <script src="./babel.min.js"></script> <script type="text/babel"> //内容 </script>
引入所需要的链接之后,就需要创建挂载点(其实就是一个带有id名的div)了,专门用于插入后续生成的内容,如下:
<div id="root"></div>
这样,一个完整的react初始模板就完成了,总结起来为三步:
(1)在页面中引入 react 库 和 react-dom 库;
(2)引入 Babel;
(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>react入门</title> </head> <body> <!-- 挂载点:后续生成的内容插入这里 --> <div id="root"></div> <!-- 引入react的js文件 --> <script src="./react.development.js"></script> <script src="./react-dom.development.js"></script> <!-- 浏览器不识别JSX,需要引入babel来解析翻译,而且需要在script写上对应属性 --> <script src="./babel.min.js"></script> <script type="text/babel"> </script> </body> </html>
2.react的封装
封装react共有三步:
(1)创建虚拟DOM对象;创建对象包含有3个参数,标签名、属性(对象格式)、标签内的内容;
(2)获取挂载点;
(3)渲染页面。
格式如下:
<body> <!-- 引入react的js文件 --> <script src="./react.development.js"></script> <script src="./react-dom.development.js"></script> <script src="./babel.min.js"></script> <!-- 挂载点:后续生成的内容插入这里 --> <div id="root"></div> <script type="text/babel"> // 1.创建虚拟DOM对象 const vNode = React.createElement( //参数表示:标签,属性(对象格式),内容 "div", { id: "mydiv", className: "cls", }, "hello react!" ); // 2.获取挂载点 const root = document.getElementById("root"); // 3.页面渲染 ReactDOM.render(vNode, root); </script> </body> </html>
此封装过程也可用JSX语法来写:
<body> <!-- 引入react的js文件 --> <script src="./react.development.js"></script> <script src="./react-dom.development.js"></script> <!-- 挂载点:后续生成的内容插入这里 --> <div id="root"></div> <!-- 浏览器不识别JSX,需要引入babel来解析翻译,而且需要在script写上对应属性 --> <script src="./babel.min.js"></script> <script type="text/babel"> // 1.创建标签对象 // JSX语法:在JS代码中写XML(类HTML) const vNode = ( <div id="mydiv" className="cls"> hello react JSX! </div> ); // 2.获取挂载点 const root = document.getElementById("root"); // 2.渲染页面 ReactDOM.render(vNode, root); </script> </body>
可以看出,JSX语法最大区别在于省去了创建虚拟DON对象的步骤,而是直接创建一个标签对象,在该标签对象中直接按照HTML格式书写代码即可,其余两步则不变。
二、组件
组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。React 定义组件有两种方式:
函数方式,rfc react function component;某些不能使用;
类方式,rcc react class component;功能更为强大;
1.函数方式定义组件
<body> <!-- 挂载点:后续生成的内容插入这里 --> <div id="root"></div> <!-- 引入react的js文件 --> <script src="./react.development.js"></script> <script src="./react-dom.development.js"></script> <!-- 浏览器不识别JSX,需要引入babel来解析翻译,而且需要在script写上对应属性 --> <script src="./babel.min.js"></script> <script type="text/babel"> // 利用函数的封装性和复用性实现组件的复用 // 规范要求:函数名称大写驼峰命名 function Hello() { return <h1>Hello 组件!</h1>; } let h = Hello(); // ------------------------------------------------------------- // JSX语法 // 复用 // JSX语法中调用函数需要写JS语法,JS语法在JSX中写时需要使用{}括起来 // h = ( // <div> // {Hello()} // {Hello()} // {Hello()} // </div> // ); // ------------------------------------------------------------- // 语法糖写法:标签方式调用(推荐) h = <Hello />; // 语法糖复用 h = ( <div> <Hello /> <Hello /> <Hello /> </div> ); // ------------------------------------------------------------- // 渲染 ReactDOM.render(h, document.getElementById("root")); </script> </body>
2.函数组件传参
<body> <!-- 挂载点:后续生成的内容插入这里 --> <div id="root"></div> <!-- 引入react的js文件 --> <script src="./react.development.js"></script> <script src="./react-dom.development.js"></script> <!-- 浏览器不识别JSX,需要引入babel来解析翻译,而且需要在script写上对应属性 --> <script src="./babel.min.js"></script> <script type="text/babel"> // 定义函数组件 // JSX语法中执行JS代码要用{}包裹 function HelloName(props) { //return <h1>Hello{props}</h1>; return <h1>Hello{props.name}</h1>; } // 调用组件 //let h = HelloName("你好"); //传值 let h = HelloName({ name: "good" }); //传对象 // ----------------------------------------------------------------------- // 语法糖写法(推荐) h = <HelloName name="语法糖调用" />; // 复用 h = ( <div> <HelloName name="语法糖调用" /> <HelloName name="推荐使用语法糖" /> </div> ); // ----------------------------------------------------------------------- // 渲染 ReactDOM.render(h, document.getElementById("root")); </script> </body>
3.类方式定义组件
<body> <!-- 挂载点:后续生成的内容插入这里 --> <div id="root"></div> <!-- 引入react的js文件 --> <script src="./react.development.js"></script> <script src="./react-dom.development.js"></script> <!-- 浏览器不识别JSX,需要引入babel来解析翻译,而且需要在script写上对应属性 --> <script src="./babel.min.js"></script> <script type="text/babel"> // 定义一个类组件 class Hello extends React.Component { //定义类继承React父类 // 类方法:类属性+类方法 // 类方法 // 默认语法糖标签调用会调用此方法(意思就是如果用语法糖写法只能用render,用其他则会报错,所以建议使用render方法) render() { return <h1>Hello 类组件!</h1>; } } // 实例化 let h = new Hello().render(); // 语法糖调用 h = <Hello />; h = ( <div> {new Hello().render()} {new Hello().render()} <Hello /> <Hello /> </div> ); // 渲染 ReactDOM.render(h, document.getElementById("root")); </script> </body>
4.类组件传参
<body> <!-- 挂载点:后续生成的内容插入这里 --> <div id="root"></div> <!-- 引入react的js文件 --> <script src="./react.development.js"></script> <script src="./react-dom.development.js"></script> <!-- 浏览器不识别JSX,需要引入babel来解析翻译,而且需要在script写上对应属性 --> <script src="./babel.min.js"></script> <script type="text/babel"> // 定义类组件并接收参数 class HelloName extends React.Component { render() { // this代表当前类内,可以通过它调用类成员 return <h1>Hello {this.props.name}</h1>; } } // 实例化 let h = new HelloName({ name: "类组件传参" }).render(); // 语法糖传参 h = <HelloName name="语法糖传参" />; // 复用 h = ( <div> {new HelloName({ name: "JS调用类组件1" }).render()} {new HelloName({ name: "JS调用类组件2" }).render()} <HelloName name="语法糖调用1" /> <HelloName name="语法糖调用2" /> </div> ); // 渲染 ReactDOM.render(h, document.getElementById("root")); </script> </body>
三、事件
React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:React 事件的命名采用小驼峰式(camelCase),而不是纯小写。使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
事件绑定使用的是JS原生写法:
<body> <!-- 挂载点:后续生成的内容插入这里 --> <div id="root"></div> <!-- 引入react的js文件 --> <script src="./react.development.js"></script> <script src="./react-dom.development.js"></script> <!-- 浏览器不识别JSX,需要引入babel来解析翻译,而且需要在script写上对应属性 --> <script src="./babel.min.js"></script> <script type="text/babel"> // 定义组件+事件处理方法 class App extends React.Component { // 类成员方法 show() { alert("点击成功!"); } render() { return ( <div> {/*this代表当前类的成员,此处show不能加括号,因为事件必须点击后执行,如果加了括号就直接执行了*/} <button onClick={this.show}>点击按钮</button> </div> ); } } // 渲染 ReactDOM.render(<App />, document.getElementById("root")); </script> </body>
事件中this的指向:严格模式下指向window,非严格模式下为undefined;
解决方式:
(1)定义普通函数,调用时 bind 替换 this 并不触发执行;
{this.add.bind(this)}
(2)也使用箭头函数来定义方法,这样正常进行调用;
//定义 add=()=>{} //调用 {this.add}
(3)定义普通函数,调用时先调用箭头函数,再由箭头函数调用普通函数。
{()=>this.add}
如下:使用bind函数替换this指向、使用箭头函数触发
<body> <!-- 挂载点:后续生成的内容插入这里 --> <div id="root"></div> <!-- 引入react的js文件 --> <script src="./react.development.js"></script> <script src="./react-dom.development.js"></script> <!-- 浏览器不识别JSX,需要引入babel来解析翻译,而且需要在script写上对应属性 --> <script src="./babel.min.js"></script> <script type="text/babel"> class App extends React.Component { // 类成员 // 属性 name = "Hello React!"; // 方法 show() { console.log("普通函数:" + this.name); } // 箭头函数方法 show1 = () => { console.log("箭头函数:" + this.name); }; render() { return ( <div> {/*用bind绑定this,bind(this)将方法中的this替换为App*/} <button onClick={this.show.bind(this)}>普通函数触发</button> <br /> <button onClick={this.show1}>箭头函数触发</button> </div> ); } } // 渲染 ReactDOM.render(<App />, document.getElementById("root")); </script> </body>