本文是『horseshoe·React专题』系列文章之一,后续会有更多专题推出
来我的
GitHub repo 浏览完全的专题文章来我的
个人博客 取得无与伦比的浏览体验
话说PHP是世界上最好的言语(笑)。
因为它的入门门坎极低。
<?php
$str = '<ul>';
foreach ($fruits as $fruit) {
$str += '<li>' . $fruit . '</li>';
}
$str += '</ul>';
?>
许多年前,这类字符串拼接开辟网页的体式格局异常盛行。
然则这类写法有两个题目:
- 轻易形成XSS注入,有极大的平安风险。
- 拼接的写法很烦琐。
因而facebook的工程师最先动歪脑筋了。
XHP
他们的处理计划也很新鲜,就是在代码里直接写标签,而不是将标签视为字符串。
前面说到,字符串拼接很轻易形成XSS注入。那末什么是XSS注入呢?
比方歹意用户输入这么一段内容:<script>code</script>
,就可能被顺序辨认为一段剧本,他能够在剧本内里干任何事情。
因而人们想到的要领是对一切输入转义,转义的作用就是让一切标签没法被辨认为标签,而只是标签写法的字符串。用户的输入就会原原本本的展现在页面上。
然则输入转义也有题目,就是轻易把字符串拼接的标签也给转义了。人人应当看过页面上大段大段的标签写法的文本吧。
我们来看看XHP的写法。
<?hh
$post =
<div class="post">
<h2>{$post}</h2>
<p><span>Hey there.</span></p>
<a href={$like_link}>Like</a>
</div>;
诶,是否是有点眼熟?
XHP把标签与字符串区分开来了,变成剧本语法的一部分。
这恰优点理了前面提到的两个题目:
- 标签就是标签,字符串就是字符串,再也别想混水摸鱼。
- 像写剧本一样写标签,是否是爽多了?
JSX
实在facebook一直在前端组件化方面做种种尝试,但都不是迥殊胜利。
直到2013年,工程师Jordan Walke提出一个斗胆勇敢的主意:把XHP的写法迁移到JavaScript中来。即使有XHP的案例在前,人人照样以为这个主意很猖獗。
不过,facebook极为优异的工程师文明终究促成了这类尝试。这一尝试不得了,开了天眼。
自此以后就开启了React的开挂之路。
const element = <h1>Hello React!</h1>;
这不就是facebook一直在苦苦求索的前端组件化计划吗?
刀耕火种时代的前端,进口是HTML,剧本和款式被引入到HTML页面上。这是一种星散化的头脑,以言语为最小颗粒。
但是经由大批痛楚的实践,人们发明以内容为最小颗粒才是正解。以组件为单元,页面构造、款式和功用都被集成在组件内部,对开辟者来说组件就是一个黑匣子,只能经由历程暴露出来的接口运用组件。这是一种封装的头脑,目标固然是为了复用。
固然,现在React还没法完成真正意义上的CSS封装,不过以当下前端的关注度,CSS被完全招抚也指日可待。
语法
标签的写法和HTML一样,只不过融入到了JavaScript中。
组件,实在就是自定义标签,首字母必需大写,为了与原生标签区分开来。
假如标签或组件没有包括内容,能够采纳自闭合标签写法。
const element = <App />;
JSX会自动疏忽false
、null
和undefined
。
标签的class
属性和for
属性要用className
属性和htmlFor
属性替代。
组件返回多个标签或多个组件必需要用一个标签或组件包裹,也就是说只能有一个顶层元素。
然则,React16以上的版本支撑用空标签包裹或许直接返回数组。如许的优点就是没必要增加许多无用的标签使页面变得越发痴肥。
import React, { Fragment } from 'react';
const App = () => {
return (
<Fragment>
<div>React</div>
<div>Vue</div>
<div>Angular</div>
</Fragment>
);
}
export default App;
import React from 'react';
const App = () => {
return (
<>
<div>React</div>
<div>Vue</div>
<div>Angular</div>
</>
);
}
export default App;
import React from 'react';
const App = () => {
return [
<div key="1">React</div>,
<div key="2">Vue</div>,
<div key="3">Angular</div>,
];
}
export default App;
表达式
标签里一定要写一些变量,要不然页面就是死的。
怎样写变量呢?用花括号围困。
const name = 'React';
const element = <h1>Hello {name}!</h1>;
假如我想插进去一个对象字面量怎样办?
很简朴,再包裹一层花括号。
const obj = { name: 'React' };
const element = <h1 style={{ color: '#f66' }}>Hello {name}!</h1>;
实际上花括号语法支撑一切的表达式。
那末题目来了,什么是表达式?
简朴来说,表达式的重要作用是盘算和声明,总是有返回值。与之相对,语句的重要作用是逻辑和行动,没有返回值。
以下表达式JSX都支撑。
const a = <button onClick={() => console.log('react')}>click</button>;
const b = <button onClick={function (){ console.log('react') }}>click</button>;
const c = <div>{popular ? 'react' : 'vue'}</div>;
const d = <div>{popular && 'react'}</div>;
const e = <div>{renderSomething()}</div>;
像赋值语句、推断语句和轮回语句JSX都不支撑。
那开辟者要衬着一个列表怎样办?
for轮回语句一定是不可的,幸亏我们有map函数。因为从上例我们晓得,JSX是支撑函数实行表达式的。
forEach函数行不可呢?不可,因为它没有返回值。也就是说,filter、find、reduce等有返回值的遍历函数都是能够的。
import React, { Component } from 'react';
const list = ['react', 'vue', 'angular'];
class App extends Component {
render() {
return (
<div>{list.map(value => <div key={value}>{value}</div>)}</div>
);
}
}
export default App;
编译
不晓得你们有无如许的疑问:
- 为何返回多个标签或组件必需要用一个标签或组件包裹?
- 为何在基础没有运用
React
这个变量的情况下还要import React
?
这里就要讲到JSX的编译。
因为JSX不是准确的JavaScript语法,它要经由编译才被浏览器辨认。
现在JSX的编译事情是由babel来完成的。
我们来看看编译都做了哪些事情。
下面的例子,后者是前者编译后的效果。
const app = (
<div className="form">
<input type="text" />
<button>click</button>
</div>
);
const app = React.createElement(
"div",
{ className: "form" },
React.createElement("input", { type: "text" }),
React.createElement(
"button",
null,
"click",
),
);
能够看到,标签末了变成了一个函数实行表达式,第一个参数是标署名,第二个参数是属性鸠合,以后的参数都是子标签。
看到这里,置信也不必我诠释了,前面提出的两个题目豁然开朗。
全部UI实际上是经由历程层层嵌套的React.createElement
要领返回的,所以我们要在文件开首import React
,不然编译后就会发明createElement
没有定义。
React.createElement
实行的效果是一个对象,对象的属性形貌了标签或组件的性状,对象再嵌套子对象。假如顶层返回多个标签,就没法表达为一个对象了。
因为React16引入了Fiber机制,使得返回多标签成为可能(并不清晰缘由)。
同时也回复了为何标签的class
属性和for
属性要用className
属性和htmlFor
属性替代。在标签里属性怎样写都无所谓,然则class
和for
是JavaScript中的关键字,所以要换一种写法。
React内里通报props有一种写法,假如通报的是一个对象,能够用扩大运算符很轻易的通报。
下面的例子,value
先是被扩大运算符将属性剖析,然后又被一个对象包裹。这里只是做了一个浅拷贝,并没有其他的寄义。所以终究通报给组件的仍然是一个对象。
所以疑问就来了,一般给组件通报属性都是键值对的情势,直接通报一个对象也能够吗?
实在一切的属性末了都邑放到一个对象内里,所以两种写法异曲同工。React只不过给了一种快捷体式格局。
相识编译的历程,许多写法都很好理解了。
const value = { a: 1, b: 2 };
const element = <App a={value.a} b={value.b} />;
const value = { a: 1, b: 2 };
const element = <App {...value} />;
React专题一览