本文记录 React 的学习过程,内容为配置环境、ES6 语法补充、Components。
React 是一个用于构建用户界面的库。React 不是一个框架,它的应用甚至不局限于 Web 开发,它可以与其他库一起使用以渲染到特定环境。
React 官网:React 。
1. React配置环境
React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作 components
。React 能够构建那些数据会随时间改变的大型应用。
React 特性:
React 为了能够方便地去维护我们的页面,它在内存里面创建了一个虚拟的 DOM 树:Virtual DOM
,这是一个轻量级的虚拟的 DOM,就是 React 抽象出来的一个对象,描述 DOM 应该什么样子的,应该如何呈现。通过这个 Virtual DOM
去更新真实的 DOM,由这个 Virtual DOM
管理真实 DOM 的更新。
数据驱动:当某一个元素里的数据发生变化后,React 会重新将有可能修改的元素都修改一遍,然后与真实的 DOM 树对比是否有区别,React 分析完后最终只会修改真实改变的结点。由于在内存里修改对象的速度很快,因此 React 效率很高。
React 一般不直接手写 JS,而是通过编写 JSX 文件,JSX 比 JS 更好写一点,React 会先将 JSX 编译成 JS。
(1)安装 Git Bash
:Windows 安装配置 Git 教程 。
(2)安装 NodeJS
:NodeJS 的安装及配置 。
(3)安装 create-react-app
:
打开 Git bash
,执行以下命令:
1 npm i -g create-react-app
如果速度很慢,可以先修改镜像源再尝试安装:
1 2 npm config set registry https://registry.npm.taobao.org npm i -g create-react-app
如果安装完成后出现警告:npm WARN deprecated tar@2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.
,可以先更新 tar
试试:
如果还是有警告,且创建项目时(例如执行 create-react-app react-app
)报错:bash: create-react-app: command not found
,使用 npx
创建项目:
1 npx create-react-app my-app
或者用 npm
创建项目:
1 npm init react-app my-app
创建好后进入项目文件夹启动项目:
启动后访问 localhost:3000
即可访问页面,ctrl+c
可停止服务。
(4)配置 VS Code 插件:Simple React Snippets、Prettier - Code formatter
Simple React Snippets
为 React 智能化自动补全插件。
例如输入 imrc
即可补全出以下内容:
1 import React , { Component } from 'react' ;
输入 cc
即可补全出以下内容:
1 2 3 4 5 6 7 8 class Example extends Component { state = { } render ( ) { return (); } } export default Example ;
Prettier - Code formatter
为代码格式化插件,安装好后在 JSX 代码中通过 VS Code 一键格式化快捷键:ctrl + k + f
即可配置格式化插件。
(5)创建 React App
:
在目标目录下右键打开 Git Bash,在终端中执行:
1 2 3 npx create-react-app react-app # react-app是新建项目的名字,可以替换为其他名称 cd react-app npm start # 启动应用
启动成功后会在本地开一个3000端口,页面效果已在上文展示。此时使用 VS Code 打开 react-app
文件夹可以看到项目的目录结构。
其中,node_modules
用来维护各种 JS 库,未来安装的所有依赖项都会放在该文件夹下;public
中的 index.html
就是我们未来渲染出的页面,该文件中只有一个 <div id="root"></div>
;src
中的 index.js
代码如下:
1 2 3 4 5 6 7 8 9 10 11 import React from 'react' ;import ReactDOM from 'react-dom/client' ;import './index.css' ;import App from './App' ;const root = ReactDOM .createRoot (document .getElementById ('root' )); root.render ( <React.StrictMode > <App /> </React.StrictMode > );
其中 App
的定义在 App.js
中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import logo from './logo.svg' ;import './App.css' ;function App ( ) { return ( <div className ="App" > <header className ="App-header" > <img src ={logo} className ="App-logo" alt ="logo" /> <p > Edit <code > src/App.js</code > and save to reload. </p > <a className ="App-link" href ="https://reactjs.org" target ="_blank" rel ="noopener noreferrer" > Learn React </a > </header > </div > ); } export default App ;
该 App
组件就定义了页面的具体内容,且我们能够发现该 JS 文件中有 HTML 代码,因此该文件即为 JSX 文件,能够在 JavaScript 的基础上支持 XML(可扩展标记语言),HTML 也是一种特殊的 XML。
JSX 是 React 中的一种语言,会被 Babel 编译成标准的 JavaScript。
2. ES6语法补充
ES6,全称 ECMAScript 6.0,是 JavaScript 的版本标准。此处添加一些 React 中常用的语法糖。
(1)使用 bind()
函数绑定 this
取值
在 JavaScript 中,函数里的 this
指向的是执行时的调用者,而非定义时所在的对象。例如:
1 2 3 4 5 6 7 8 9 10 11 const person = { name : "abc" , talk : function ( ) { console .log (this ); } } person.talk (); const talk = person.talk ;talk ();
运行结果为:
1 2 {name: 'abc', talk: f} undefined
使用 bind()
函数绑定 this
的取值为 person
。例如:
1 const talk = person.talk .bind (person);
运行结果为:
1 2 {name: 'abc', talk: f} {name: 'abc', talk: f}
(2)箭头函数的简写方式
当函数参数只有一个时可以将括号去掉,当函数体只有一个 return
语句时可以把 return
和 {}
一起去掉,例如:
1 2 3 const f = (x ) => { return x * x; };
等价于:
(3)箭头函数不重新绑定 this
的取值
1 2 3 4 5 6 7 8 9 const person = { talk : function ( ) { setTimeout (function ( ) { console .log (this ); }, 1000 ); } }; person.talk ();
1 2 3 4 5 6 7 8 9 const person = { talk : function ( ) { setTimeout (() => { console .log (this ); }, 1000 ); } }; person.talk ();
(4)对象的解构
1 2 3 4 5 6 7 const person = { name : "abc" , age : 18 , height : 180 , }; const {name : new_name, age} = person;
(5)数组和对象的展开
1 2 3 4 5 6 7 let a = [1 , 2 , 3 ];let b = [...a]; let c = [...a, 4 , 5 , 6 ]; let d = {name : "abc" };let e = {age : 18 , height : 180 };let f = {...d, ...e, weight : 120 };
(6)Named exports 与 Default exports
Named Export
:可以 export
多个,import
的时候需要加大括号,名称需要匹配,即之前使用的方式。
Default Export
:最多 export
一个,import
的时候不需要加大括号,可以直接定义别名。
3. Components
React 应用程序是由组件 (Component)组成的。组件是一段可重用代码,一个组件是 UI(用户界面)的一部分,它拥有自己的逻辑和外观,用于渲染、管理和更新应用中的 UI 元素。组件可以小到一个按钮,也可以大到整个页面。
(1)创建项目
首先创建一个新项目 box-app
:
1 2 3 npx create-react-app box-app cd box-app npm start
安装 bootstrap
库:
bootstrap
的引入方式:
1 import 'bootstrap/dist/css/bootstrap.css' ;
(2)创建 Component
在 src
文件夹中创建一个文件夹 components
存放组件,然后在 components
文件夹中创建一个 JSX 文件 box.jsx
(使用 .js
后缀也一样,只是用 .jsx
后区分起来跟明显一点)其框架如下:
1 2 3 4 5 6 7 8 9 10 import React , { Component } from 'react' ; class Box extends Component { state = { } render ( ) { return (<h1 > Hello World!</h1 > ); } } export default Box ;
然后我们需要在 index.js
中将组件渲染出来:
1 2 3 4 5 6 7 8 9 10 11 12 import React from 'react' ;import ReactDOM from 'react-dom/client' ;import './index.css' ;import 'bootstrap/dist/css/bootstrap.css' ;import Box from './components/box' ;const root = ReactDOM .createRoot (document .getElementById ('root' ));root.render ( <React.StrictMode > <Box /> </React.StrictMode > );
(3)创建按钮
由于 Component 中的 render()
函数只能 return
一个元素,因此当子节点数量大于1时,可以用 <div>
或 <React.Fragment>
将其括起来。
(4)内嵌表达式
JSX 中使用 {}
在 HTML 标签中嵌入表达式。
(5)设置属性
由于 class
是 JS 中的关键字,因此 HTML 标签中的 class
需要改为 className
。CSS 属性也需要修改,例如:background-color
修改为 backgroundColor
,其它属性也是类似的。
以上的综合示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import React , { Component } from 'react' ; class Box extends Component { state = { x : 0 }; styles = { width : '50px' , height : '50px' , backgroundColor : 'lightblue' , color : 'white' , textAlign : 'center' , lineHeight : '50px' , borderRadius : '5px' }; render ( ) { return ( <React.Fragment > <div style ={this.styles} > {this.state.x}</div > <button className ='btn btn-primary m-2' > Left</button > <button className ='btn btn-success m-2' > Right</button > </React.Fragment > ); } } export default Box ;
(6)数据驱动改变 Style
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import React , { Component } from 'react' ; class Box extends Component { state = { x : 1 }; render ( ) { return ( <React.Fragment > <div style ={this.getStyles()} > {this.state.x}</div > <button className ='btn btn-primary m-2' > Left</button > <button className ='btn btn-success m-2' > Right</button > </React.Fragment > ); } getStyles ( ) { let styles = { width : '50px' , height : '50px' , backgroundColor : 'lightblue' , color : 'white' , textAlign : 'center' , lineHeight : '50px' , borderRadius : '5px' }; if (this .state .x === 0 ) { styles.backgroundColor = 'orange' ; } return styles; } } export default Box ;
(7)渲染列表
可以使用 map
函数渲染一个列表,每个元素需要具有唯一的 key
属性,用来帮助 React 快速找到被修改的 DOM 元素,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import React , { Component } from 'react' ; class Box extends Component { state = { x : 1 , colors : ['red' , 'green' , 'blue' ] }; render ( ) { return ( <React.Fragment > <div > {this.state.x}</div > <button className ='btn btn-primary m-2' > Left</button > <button className ='btn btn-success m-2' > Right</button > {this.state.colors.map(color => ( <div key ={color} > {color}</div > ))} </React.Fragment > ); } } export default Box ;
(8)Conditional Rendering
利用逻辑表达式的短路原则:
与表达式中 expr1 && expr2
,当 expr1
为假时返回 expr1
的值,否则返回 expr2
的值。
或表达式中 expr1 || expr2
,当 expr1
为真时返回 expr1
的值,否则返回 expr2
的值。
(9)绑定事件
例如可以使用 onClick
绑定按钮的点击事件,注意需要妥善处理好绑定事件函数的 this
,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import React , { Component } from 'react' ; class Box extends Component { state = { x : 1 }; handleClickLeft ( ) { console .log ('click left' , this ); } handleClickRight = () => { console .log ('click right' , this ); } render ( ) { return ( <React.Fragment > <div > {this.state.x}</div > <button onClick ={this.handleClickLeft} className ='btn btn-primary m-2' > Left</button > <button onClick ={this.handleClickRight} className ='btn btn-success m-2' > Right</button > </React.Fragment > ); } } export default Box ;
(10)修改 state
需要使用 this.setState()
函数,每次调用 this.setState()
函数后,会自动重新调用 this.render()
函数,用来修改虚拟 DOM 树。React 只会修改不同步的实际 DOM 树节点。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import React , { Component } from 'react' ; class Box extends Component { state = { x : 1 }; handleClickLeft = () => { this .setState ({ x : this .state .x - 1 }); } handleClickRight = () => { this .setState ({ x : this .state .x + 1 }); } render ( ) { return ( <React.Fragment > <div style ={this.getStyles()} > {this.state.x}</div > <button onClick ={this.handleClickLeft} className ='btn btn-primary m-2' > Left</button > <button onClick ={this.handleClickRight} className ='btn btn-success m-2' > Right</button > </React.Fragment > ); } getStyles ( ) { let styles = { width : '50px' , height : '50px' , backgroundColor : 'lightblue' , color : 'white' , textAlign : 'center' , lineHeight : '50px' , borderRadius : '5px' , position : 'relative' , left : this .state .x }; if (this .state .x === 0 ) { styles.backgroundColor = 'orange' ; } return styles; } } export default Box ;
(11)给事件函数添加参数
可以定义一个临时函数绑定事件,然后在该函数中调用原函数并传入参数,或者直接在绑定事件的时候用一个临时的箭头函数返回传入参数的原函数。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 import React , { Component } from 'react' ; class Box extends Component { state = { x : 1 }; handleClickLeft = (step ) => { this .setState ({ x : this .state .x - step }); } handleClickRight = (step ) => { this .setState ({ x : this .state .x + step }); } handleClickLeftTmp = () => { this .handleClickLeft (10 ); } render ( ) { return ( <React.Fragment > <div style ={this.getStyles()} > {this.state.x}</div > <button onClick ={this.handleClickLeftTmp} className ='btn btn-primary m-2' > Left</button > <button onClick ={() => this.handleClickRight(10)} className='btn btn-success m-2'>Right</button > </React.Fragment > ); } getStyles ( ) { let styles = { width : '50px' , height : '50px' , backgroundColor : 'lightblue' , color : 'white' , textAlign : 'center' , lineHeight : '50px' , borderRadius : '5px' , position : 'relative' , left : this .state .x }; if (this .state .x === 0 ) { styles.backgroundColor = 'orange' ; } return styles; } } export default Box ;
上一章:Web学习笔记-JavaScript 。
下一章:Web学习笔记-React(组合Components) 。