文章目录
重点大纲提炼
- JSX
- 声明式UI编写
- 语法
- 怎么输出数据
- {表达式}
- 针对不同的数据输出会有不同的表现
- 列表
- 逻辑输出
React介绍
一个用于构建用户界面的 JavaScript 库
起源
React
起源于 Facebook
的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,做出来以后,发现这套东西很好用,就在2013年5月开源了,随后越来越多人开始关注和使用 React
,慢慢的 React
就成为了当前最流行的前端开发框架之一。
特点
React
采用了声明式编程范式,可以更加方便的构建UI
应用- 内部封装更加高效的与底层
DOM
进行交互的逻辑,提高性能的同时也能帮助我们更加专注于业务 - 可以很好的接纳其它框架或库与其进行配合
React 全家桶
React
: 提供框架(库)核心功能,如组件
、虚拟DOM
等create-react-app
: 脚手架,提供一套用于快速 构建和打包React
项目的工具react-router
: 基于React
的路由库redux、react-redux
: 状态管理库
初识 React 与 JSX
加载引入
- 基于浏览器 <script> 的模式
- 基于自动化的集成环境模式
基于浏览器 script
的模式
React.js 框架本身包含两个部分
- react.js:提供 React.js 核心功能代码,如:虚拟 dom,组件
- 封装了很多底层的函数,核心类,但这些通通都与环境无关,跟操作浏览器原生app无关的一些东西,而是核心的东西。
- 除此之外还提供了react dom,它提供了对不同环境的封装,比如dom操作。即主件这个东西,本身是与浏览器无关的,它只是定义了一个主件结构,放在核心库中。像虚拟dom,通通与浏览器无关,无论在浏览器中用,还是在原生app中用,它都有组件的概念和组件的代码
- react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码(React不只是仅仅在浏览器中去应用,<React Native>同时还可以运用在手机端
- react-dom.js:提供了与浏览器交互的 DOM 功能,如:dom 渲染
- 基于web的,封装与浏览器打交道的相关代码,渲染,事件
起手式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="./js/react.development.js"></script>
<script src="./js/react-dom.development.js"></script>
<script src="./src/1.js"></script>
<script>
// 类似模板引擎的render,是渲染界面用的!
// 第一个参数:渲染的内容 第二个参数:渲染内容放置在页面的什么位置
ReactDOM.render(
//'<div>我要渲染的内容</div>',
'我要渲染的内容',
document.querySelector('#app')
);
</script>
</body>
</html>
我们不能仅仅渲染字符串,而需要渲染html元素等。
// 类似模板引擎的render,是渲染界面用的!
// 第一个参数:渲染的内容 第二个参数:渲染内容放置在页面的什么位置
ReactDOM.render(
'<div>我要渲染的内容</div>',
// '我要渲染的内容',
document.querySelector('#app')
);
发现达不到预期结果,它只能最终解析为字符串!为什么这样设计呢?参考下面的**XSS
**
为了更方便输出html以及为后续的一些功能作准备,如组件化、虚拟dom,在这里它提供了一套新的模板语法。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="./js/react.production.min.js"></script>
<script src="./js/react-dom.production.min.js"></script>
<script src="js/app.js"></script>
</body>
</html>
js/app.js
ReactDOM.render(
'<div>我要渲染的内容</div>',
document.getElementById('app')
);
ReactDOM.render
ReactDOM.render(element, container[, callback])
element:要渲染的内容
container:要渲染的内容存放容器
callback:渲染后的回调函数
XSS
为了有效的防止 XSS
注入攻击,React DOM
会在渲染的时候把内容(字符串)进行转义,所以字符串形式的标签是不会作为 HTML
标签进行处理的
编程范式
就是编程的一种模式,比较流行的一些编程范式
- 命令式编程
- 声明式编程
- 函数式编程
- …
命令式编程
告诉计算机怎么做(How?) - 过程
在前面所学的原生 WebComponent 中,我们 UI 的构建是使用了命令式的编程方式来完成的
let shadow = this.attachShadow({mode: 'open'});
let style = document.createElement('style');
style.textContent = `span {color:red}`;
let span = document.createElement('span');
span.innerHTML = '我是自定义元素的内容';
span.classList.add('cred');
shadow.appendChild(style);
shadow.appendChild(span);
声明式编程
告诉计算机我们要什么(What?) - 结果
SELECT * FROM `USER` WHERE `gender`='男' ORDER BY `age` DESC;
上面的 SQL 就是一个典型的声明式编程,告诉数据库,我要什么结果,至于怎么查询出来结果,排序如何实现的过程 SQL 并不关心,由内部(底层)实现
['k',1,2,'k',true,'b'].filter(v => Number.isFinite(v)).map(v=>v*10).reduce((c, v)=>c + v, 0);
React.js 中的声明式 UI
<span className="cred">我是自定义元素的内容</span>
使用 JSX
JSX
是一个基于 JavaScript
+ XML
的一个扩展语法
- 它可以作为
值
使用 - 它并不是
字符串
- 它也不是
HTML
- 它可以配合
JavaScript 表达式
一起使用
js/app.js
ReactDOM.render(
<div>我要渲染的内容</div>,
document.getElementById('app')
);
引入 JSX 解析库
babel-standalone.js:在浏览器中处理 JSX
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel" src="js/app.js"></script>
注意:如果包含或引入的代码中包含
JSX
,需要设置script
标签的type
属性为:text/babel
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts等语法 -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
/**
* JSX
* JavaScript + XML
*/
ReactDOM.render(
<div>我要渲染的内容</div>,
document.querySelector('#app')
);
</script>
</body>
</html>
DOM 对象与 Virtual DOM
JSX 通过编译器会最终转成一个对象给我们 - VDOM(虚拟DOM)
DOM 对象
浏览器会把页面中的元素映射为 JavaScript 中的对象,在 JavaScript 中通过对这些对象的访问来获取页面中对应元素及其内容。同时,对这些对象进行某些操作,又会反馈到页面中对应的元素上面。
但是,原生 JavaScript DOM 对象内容和结构太复杂,有很多的特性是我们平时很少用到的,而且我们对对象的操作会立即反馈到页面(渲染),影响性能
虚拟 DOM
virtual DOM,参考原生 DOM 对象构建的一个对象,它的结构足够简单,同时优化渲染逻辑,减少变化带来的渲染性能影响
const App = (
<div>
<h1>开发</h1>
<p>web前端高级工程师</p>
</div>
);
生成的 virtual DOM 结构如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
/**
* JSX
* JavaScript + XML
*
* JSX 通过编译器会最终转成一个对象给我们 - VDOM(虚拟DOM)
*/
let div = <div>我要渲染的内容</div>;
console.log(div);
ReactDOM.render(
div,
document.querySelector("#app")
);
</script>
</body>
</html>
这就是实际上的虚拟dom了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
/**
* JSX
* JavaScript + XML
*
* JSX 通过编译器会最终转成一个对象给我们 - VDOM(虚拟DOM)
*/
let div = <div>我要渲染的内容</div>;
let appElement = document.querySelector('#app');
console.dir(appElement);
console.log(div);
ReactDOM.render(
div,
// document.querySelector("#app")
appElement
);
</script>
</body>
</html>
我们这样就看到真实dom元素了,它是页面中真实存在的dom对象。这个对象表示了页面的一些元素的信息,但是原生当中的dom对象东西特别多,非常复杂。实际上在做模板渲染的时候,压根不需要如此多的信息。我们最需要关注的几个信息:
- 啥标签?
- 标签类型:文本/元素
- 标签属性
- 标签嵌套内容
我们通过模板写的标签,直接会被react转换为虚拟dom。因为真实dom比较大,一定程度上会影响性能等因素。毕竟操作dom的开销是比较大的,所以jsx首先做的事情,就是把模板转化成虚拟dom。在必要的时候,再把虚拟dom变为真实dom。在这个整个过程当中,对页面当中一些操作,如对数据的一些变更,都会使模板发生变化。模板变化以后,react会判断哪些地方是需要更新的,哪些地方树不需要更新的,而且判断是基于很小的虚拟dom进行的,所以开销相对于原生js而言很小。即用一个很小的对象,降低dom频繁更新频繁操作带来的性能损耗问题。
虚拟dom大致结构:
let div = <div id="div1" style={{color: 'red'}}><span>我要渲染的内容</span><strong>123</strong></div>;
{
type: 'div',
props: {id: 'div1'}
.....(存放标签中的各个属性)
}
该对象的props
有一个id
为’div1’。
style
是一个对象属性,存放样式。
children
是标签里面嵌套的内容。
我们仔细观察,里面的嵌套的children,有时一个虚拟dom,是层层嵌套的结构。
最终ReactDOM.render
利用虚拟dom的结构去渲染页面,它会遍历该对象,首先看type,根据type如果是div就利用原生js创建一个div。紧接着再看它的props下的children,就这样层层递归的去创建。最后将创建好的真实dom渲染到指定的appElement
元素里面去。
JSX 语法规则
结构
每一个独立 JSX
结构的顶层有且只能有一个顶级父元素
// 错误
const App = (
<div>
<h1>开发</h1>
<p>web前端高级工程师</p>
</div>
<div>第二个</div>
);
// 正确
const App = (
<div>
<div>
<h1>开发</h1>
<p>web前端高级工程师</p>
</div>
<div>第二个</div>
</div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
// 正确结构
let div1 = <div>
这是内容1
</div>;
let div2 = <div>
这是内容2
</div>;
// div3的结构是错误的
let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
div,
appElement
);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
// 正确结构
let div1 = <div>
这是内容1
</div>;
let div2 = <div>
这是内容2
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
</div>,
appElement
);
</script>
</body>
</html>
在 JSX 中嵌入表达式(插值表达式)
在 JXS
中可以使用 {表达式} 嵌入JavaScript
表达式(与VUE一样)
表达式:产生值的一组代码的集合
- 变量
- 算术运算
- 函数调用
- ……
let name = '开发岗位';
let title = 'web前端高级工程师';
const App = (
<div>
<h1>{name}</h1>
<p>{title}</p>
</div>
);
注意:分清楚 表达式 与 语句 的区别,if、for、while 这些都是语句,JSX 不支持语句
<h1>{if (true) {...}</h1> // 错误
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '开发岗位';
let title = 'web前端高级工程师';
// 正确结构
let div1 = <div>
这是内容1 :{name}
</div>;
let div2 = <div>
这是内容2 :{title}
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
</div>,
appElement
);
</script>
</body>
</html>
还可以用算术运算表达式嵌入:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '开发岗位';
let title = 'web前端高级工程师';
// 正确结构
let div1 = <div>
这是内容1 :{name}
</div>;
let div2 = <div>
这是内容2 :{title}
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
</div>,
appElement
);
</script>
</body>
</html>
除此之外,还有函数调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '开发岗位';
let title = 'web前端高级工程师';
// 正确结构
let div1 = <div>
这是内容1 :{name}
</div>;
let div2 = <div>
这是内容2 :{title}
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
</div>,
appElement
);
</script>
</body>
</html>
JSX 语法示例
在 JSX
中,表达式输出的内容类型与使用位置也有一些区别
JSX 中的注释
<div>
{/*注释*/}
{/*
多行注释
*/}
</div>
输出数据类型
- 字符串、数字:原样输出
- 数组:转成字符串,数组.join(’’)
- 使用 空字符串 而不是默认的 逗号 连接
- 其它对象不能直接输出
- 布尔值、空、未定义 会被忽略
看一下数组表达式输出:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '开发岗位';
let title = 'web前端高级工程师';
// 正确结构
let div1 = <div>
这是内容1 :{name}
</div>;
let div2 = <div>
这是内容2 :{title}
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
</div>,
appElement
);
</script>
</body>
</html>
实际这里内部调用了类似数组.join('')
,使用空字符代替了逗号连接。
['a','b','c'].toString()
假如想输出对象:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '开发岗位';
let title = 'web前端高级工程师';
let user = {username: 'ls', gender: '男'};
// 正确结构
let div1 = <div>
这是内容1 :{name}
</div>;
let div2 = <div>
这是内容2 :{title}
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{user}
</div>,
appElement
);
</script>
</body>
</html>
报错了!
如何把数组输出ul
和li
的形式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '开发岗位';
let title = 'web前端高级工程师';
let user = {username: 'ls', gender: '男'};
let list = ['aaa', 'bbb', 'ccc'];
// 正确结构
let div1 = <div>
这是内容1 :{name}
</div>;
let div2 = <div>
这是内容2 :{title}
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
function renderList() {
let lis = [];
list.forEach( item => {
lis.push(<li>{item}</li>);
} );
// [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
return lis;
}
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{/*user*/}
<hr />
<ul>
{renderList()}
</ul>
</div>,
appElement
);
</script>
</body>
</html>
警告是key
的缘故,暂时放下。
这个方法我们还可以进行简化:
function renderList() {
return list.map( item => <li>{item}</li> );
}
其实没必要套函数,直接用就行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '开发岗位';
let title = 'web前端高级工程师';
let user = {username: 'ls', gender: '男'};
let list = ['aaa', 'bbb', 'ccc'];
// 正确结构
let div1 = <div>
这是内容1 :{name}
</div>;
let div2 = <div>
这是内容2 :{title}
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
// function renderList() {
// let lis = [];
//
// list.forEach( item => {
// lis.push(<li>{item}</li>);
// } );
//
// // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
// return lis;
// }
// function renderList() {
// return list.map( item => <li>{item}</li> );
// }
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{/*user*/}
<hr />
<ul>
{list.map( item => <li>{item}</li> )}
</ul>
</div>,
appElement
);
</script>
</body>
</html>
在属性上使用 表达式
JSX 中的表达式也可以使用在属性上,但是使用的时候需要注意
- 当在属性中使用 {} 的时候,不要使用引号包含
let id = 'aaaaaa';
// 错误
const App = (
<div id="{id}"></div>
);
// 正确
const App = (
<div id={id}></div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '开发岗位';
let title = 'web前端高级工程师';
let user = {username: 'ls', gender: '男'};
let list = ['aaa', 'bbb', 'ccc'];
let divId = 'aaaaa';
// 正确结构
let div1 = <div>
这是内容1 :{name}
</div>;
let div2 = <div>
这是内容2 :{title}
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
// function renderList() {
// let lis = [];
//
// list.forEach( item => {
// lis.push(<li>{item}</li>);
// } );
//
// // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
// return lis;
// }
// function renderList() {
// return list.map( item => <li>{item}</li> );
// }
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{/*user*/}
<hr />
<ul>
{list.map( item => <li>{item}</li> )}
</ul>
<hr />
<div id={divId}>CSDN</div>
</div>,
appElement
);
</script>
</body>
</html>
- JSX 更偏向 JavaScript, 所以对于一些特殊的属性,使用的是 JavaScript 中的属性名风格
// 错误
const App = (
<div class="box1"></div>
);
// 正确
const App = (
<div className="box1"></div>
);
- 为了更加方法的操作元素的 style,针对 style 这个属性有特殊的处理
const App = (
<div style={{width: '100px', height: '100px', color:'red'}}></div>
);
这里的两个 {{}} ,外部的大括号表示的是前面说的表达式语法中的大括号,里面的大括号是表示对象的大括号
let skin = {width: '100px', height: '100px', color:'red'};
const App = (
<div style={skin}></div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '开发岗位';
let title = 'web前端高级工程师';
let user = {username: 'ls', gender: '男'};
let list = ['aaa', 'bbb', 'ccc'];
let divId = 'aaaaa';
let style = {color: 'red', background: 'yellow'};
// 正确结构
let div1 = <div>
这是内容1 :{name}
</div>;
let div2 = <div>
这是内容2 :{title}
</div>;
// div3的结构是错误的
// let div3 = <div>111</div><div>222</div>;
// function renderList() {
// let lis = [];
//
// list.forEach( item => {
// lis.push(<li>{item}</li>);
// } );
//
// // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
// return lis;
// }
// function renderList() {
// return list.map( item => <li>{item}</li> );
// }
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{/*user*/}
<hr />
<ul>
{list.map( item => <li>{item}</li> )}
</ul>
<hr />
<div id={divId}>CSDN</div>
<hr />
<p style={style}>这是内容</p>
<p style={{color: 'red', background: 'yellow'}}>这是内容</p>
</div>,
appElement
);
</script>
</body>
</html>
列表渲染
如果需要渲染一组数据,我们可以通过遍历(数组遍历、对象变量……)等操作,返回一组 JSX
数据
let lisi = {
name: '李四',
gender: '男',
skills: ['JavaScript', 'Node.js'],
interests: ['音乐', '足球', '编程']
};
数组
function getSkills() {
return (
<ul>
{lisi.skills.map(skill => <li>{skill}</li>)}
</ul>
);
}
const App = (
<div>{getSkills()}</div>
);
// 或者
const App = (
<div>
<ul>
{lisi.skills.map(skill => <li>{skill}</li>)}
</ul>
</div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts等语法 -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let lisi = {
name: '李四',
gender: '男',
skills: ['JavaScript', 'Node.js'],
interests: ['音乐', '足球', '编程']
};
function getSkills() {
return (
<ul>
{lisi.skills.map(skill => <li>{skill}</li>)}
</ul>
);
}
const App = (
<div>{getSkills()}</div>
);
ReactDOM.render(
App,
document.querySelector('#app')
);
</script>
</body>
</html>
对象
function getKeys() {
let arr = [];
for (let k in lisi) {
arr.push(<li>{k}</li>);
}
return arr;
}
const App = (
<div>
<ul>
{getKeys()}
</ul>
</div>
);
// 或者
const App = (
<div>
<ul>
{Object.keys(lisi).map(key => <li>{key}</li>)}
</ul>
</div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts等语法 -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let lisi = {
name: '李四',
gender: '男',
skills: ['JavaScript', 'Node.js'],
interests: ['音乐', '足球', '编程']
};
function getKeys() {
let arr = [];
for (let k in lisi) {
arr.push(<li>{k}</li>);
}
return arr;
}
const App = (
<div>
<ul>
{getKeys()}
</ul>
</div>
);
ReactDOM.render(
App,
document.querySelector('#app')
);
</script>
</body>
</html>
以上代码,实际都会警告,实际是我们没有加key。
key
默认情况下,React 从性能上考虑,会尽可能的复用结构,针对 同组可变列表 结构,为了避免出现某些方面的问题,通常会给每一个列表添加一个 唯一的 key
<ul> {[{id:1,name:'lisi',id:2,name:'zhangsan'}].map(user => <li key={user.id}>{user.name}</li>)} </ul>
注意:key 的值不推荐使用数组的下标,具体原因,末尾最后详细解释
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let list = ['aaa', 'bbb', 'ccc'];
ReactDOM.render(
<ul>
{
list.map( (item) => {
return <li>{item}</li>
})
}
</ul>,
appElement
);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let list = ['aaa', 'bbb', 'ccc'];
function List() {
return <ul>
{
list.map( (item) => {
return <li><input type="checkbox"/> {item}</li>
})
}
</ul>
}
ReactDOM.render(
<List/>,
appElement
);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封装与浏览器打交道的相关代码,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
function List(props) {
return <ul>
{
props.data.map( item => {
return <li><input type="checkbox" /> {item}</li>
} )
}
</ul>
}
class App extends React.Component {
constructor() {
super();
this.state = {
list:['aaa', 'bbb', 'ccc']
}
}
render() {
return <div>
<List data={this.state.list} />
<button onClick={() => {
this.setState({
list: this.state.list.sort((a, b) => Math.random() - .5)
})
}}>按钮</button>
</div>
}
}
ReactDOM.render(
<App />,
appElement
);
</script>
</body>
</html>
发现了奇怪的问题。li
随机排序后,勾选状态原地不动。
首先根据传进去的数据,会渲染页面li
。当数据发生变化,页面就会更新。调用this.setState
方法后就表明数据发生了变化,它就会更新与这个数据有关的所有组件。React不会刷新整个页面,而是更新变化的部分。但是仅仅更新变化的部分,有用吗?它还考虑了复用问题,为了让性能更优,它在这里尽可能的去复用结构。
要是按照以前的思维,就是产生新的一组li覆盖旧的li,用innerHtml覆盖掉全部。
我们仔细观察,发现变化的是内容。它并没有把li替换掉,li标签及里嵌套的input标签都不会变,它只变化需要变化的部分。React为什么这么做?完全是为了复用,为了不要频繁地移动、删除、修改元素,而尽可能地原位复用元素。这样做的话,是性能优化了,但是对于同组结构(同级别的兄弟节点)而言,就会带来很大的问题,特别是循环的过程中,循环生成的结构,会带来很多问题。如这里的勾选状态是在html上的,它与数据毫无关系,因此它不会根据数据而重新渲染,即勾选状态不会随着数据变化,实际上元素与数据没有关系。
但是大部分情况下这种特效是很好的,但是在循环列表中,它是有问题的。为了解决这个问题,达到更高的复用性,就增加了一个key
属性。key
一定不能写死,它是用来标识数据与产生元素之间的关联性的,即它们之间的纽带和桥梁。但是key
必须胃一值,否则也会识别不出关联性了。
props.data.map( item => {
return <li key={item}><input type="checkbox" /> {item}</li>
} )
如果不关注这个特性,也可不用key
。如循环一个列表,其上方没有checkbox
,我们对其进行升序和降序排列,这个时候就没任何影响,因为我们需要显示的也是数据。但是如果数据与节点有关联的话,就必须使用key
了。
如果我们在这里使用索引为key
,也是没有用的。因为索引也是可复用的,数据内容变化并不会带着索引的。
props.data.map( (item, index) => {
return <li key={index}><input type="checkbox" /> {item}</li>
} )
条件渲染
function moreInterests() {
if (lisi.interests.length > 2) {
return <a href="#">更多</a>
}
}
const App = (
<div>
爱好:{lisi.interests.map(interest=>{
return <span style={{marginRight:"10px"}}>{interest}</span>
})}
{moreInterests()}
</div>
);
三元运算符
const App = (
<div>
爱好:{lisi.interests.map(interest=>{
return <span style={{marginRight:"10px"}}>{interest}</span>
})}
{lisi.interests.length > 2 ? <a href="#">更多</a> : null}
</div>
);
与或运算符
const App = (
<div>
爱好:{lisi.interests.map(interest=>{
return <span style={{marginRight:"10px"}}>{interest}</span>
})}
{lisi.interests.length > 2 && <a href="#">更多</a>}
{lisi.interests.length < 4 || <a href="#">更多</a>}
</div>
);
(后续待补充)