React中JSX的理解

React中JSX的理解

JSX是快速生成react元素的一种语法,实际是React.createElement(component,props,...children)的语法糖,同时JSX也是Js的语法扩展,包含所有Js功能。

描述

JSX发展过程

在之前,FacebookPHP大户,所以React最开始的灵感就来自于PHP
2004年这个时候,大家都还在用PHP的字符串拼接来开发网站。

$str = "<ul>";
foreach ($talks as $talk) {
  $str += "<li>" . $talk->name . "</li>";
}
$str += "</ul>";

这种方式代码写出来不好看不说,还容易造成XSS等安全问题。应对方法是对用户的任何输入都进行转义Escape,但是如果对字符串进行多次转义,那么反转义的次数也必须是相同的,否则会无法得到原内容,如果又不小心把HTML标签给转义了,那么HTML标签会直接显示给用户,从而导致很差的用户体验。
到了2010年,为了更加高效的编码,同时也避免转义HTML标签的错误,Facebook开发了XHPXHP是对PHP的语法拓展,它允许开发者直接在PHP中使用HTML标签,而不再使用字符串。

$content = <ul />;
foreach ($talks as $talk) {
  $content->appendChild(<li>{$talk->name}</li>);
}

这样的话,所有HTML标签都使用不同于PHP的语法,我们可以轻易的分辨哪些需要转义哪些不需要转义。不久的后来,Facebook的工程师又发现他们还可以创建自定义标签,而且通过组合自定义标签有助于构建大型应用。
到了2013年,前端工程师Jordan Walke向他的经理提出了一个大胆的想法:把XHP的拓展功能迁移到Js中,首要任务是需要一个拓展来让Js支持XML语法,该拓展称为JSX。因为当时由于Node.jsFacebook已经有很多实践,所以很快就实现了JSX

const content = (
  <TalkList>
    {talks.map(talk => <Talk talk={talk} />)}
  </TalkList>
);

为何使用JSX

React认为渲染逻辑本质上与其他UI逻辑内在耦合,比如在UI中需要绑定处理事件、在某些时刻状态发生变化时需要通知到UI,以及需要在UI中展示准备好的数据。
React并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为组件的松散耦合单元之中,来实现关注点分离。
React不强制要求使用JSX,但是大多数人发现,在JavaScript代码中将JSXUI放在一起时,会在视觉上有辅助作用,它还可以使React显示更多有用的错误和警告消息。
简单来说,JSX可以很好的描述页面html结构,很方便的在Js中写html代码,并具有Js的全部功能。

优点

JSX的优点主要体现在以下三点:

  • 快速,JSX执行更快,因为它在编译为JavaScript代码后进行了优化。
  • 安全,与JavaScript相比,JSX是静态类型的,大多是类型安全的。使用JSX进行开发时,应用程序的质量会变得更高,因为在编译过程中会发现许多错误,它也提供编译器级别的调试功能。
  • 简单,语法简洁,上手容易。

JSX实例

规则定义

JSX中定义了一些规则以及用法:

  • JSX只能有一个根元素,JSX标签必须是闭合的,如果没有内容可以写成自闭和的形式<div />
  • 可以在JSX通过{}嵌入Js表达式。
  • JSX会被babel转换成React.createElement的函数调用,调用后会创建一个描述HTML信息的Js对象。
  • JSX中的子元素可以为字符串字面量。
  • JSX中的子元素可以为JSX元素。
  • JSX中的子元素可以为存储在数组中的一组元素。
  • JSX中的子元素可以为Js表达式,可与其他类型子元素混用;可用于展示任意长度的列表。
  • JSX中的子元素可以为函数及函数调用。
  • JSX中的子元素如果为boolean/null/undefined将会被忽略,如果使用&&运算符,需要确保前面的是布尔值,如果是0/1则会被渲染出来。
  • 在对象属性中定义React组件,可以使用object的点语法使用该组件。
  • React元素会被转换为调用React.createElement函数,参数是组件,因此React和该组件必须在作用域内。
  • React元素需要大写字母开头,或者将元素赋值给大小字母开头的变量,小写字母将被认为是HTML标签。
  • 不能使用表达式作为React元素类型,需要先将其赋值给大写字母开头的变量,再把该变量作为组件。

JSX的使用

在示例中我们声明了一个名为name的变量,然后在JSX中使用它,并将它包裹在大括号中。在JSX语法中,可以在大括号内放置任何有效的JavaScript表达式。例如2 + 2user.firstNameformatName(user)都是有效的JavaScript表达式。

const name = "Josh Perez";
const element = <h1>Hello,{name}</h1>;

ReactDOM.render(
  element,document.getElementById("root")
);

同样JSX也是一个表达式,JSX天生就是需要被编译之后才可以使用的,在编译之后JSX表达式会被转为普通JavaScript函数调用,并且对其取值后得到JavaScript对象。也就是说,你可以在if语句和for循环的代码块中使用JSX,将JSX赋值给变量,把JSX当作参数传入,以及从函数中返回JSX

function getGreeting(user) {
  if (user) {
    return <h1>Hello,{formatName(user)}!</h1>;
  }
  return <h1>Hello,Stranger.</h1>;
}

通常可以通过使用引号来将属性值指定为字符串字面量,也可以使用大括号来在属性值中插入一个JavaScript表达式,在属性中嵌入JavaScript表达式时,不要在大括号外面加上引号。因为JSX语法上更接近JavaScript而不是HTML,所以React DOM使用camelCase小驼峰命名来定义属性的名称,而不使用HTML属性名称的命名约定。例如JSX里的class变成了className,而tabindex则变为tabIndex

const element1 = <div tabIndex="0"></div>;
const element2 = <img src={user.avatarUrl}></img>;

JSX中也可以使用</>来闭合标签,另外JSX同样也可以直接定义很多子元素。

const element1 = <img src={user.avatarUrl} />;
const element2 = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);

你可以安全地在JSX当中插入用户输入内容,React DOM在渲染所有输入内容之前,默认会进行转义,这样可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容,所有的内容在渲染之前都被转换成了字符串,可以有效地防止 XSS跨站脚本攻击。

const title = response.potentiallyMaliciousInput;
// 直接使用是安全的:
const element = <h1>{title}</h1>;

实际上Babel会把JSX转译成一个名为React.createElement()函数调用,通过React.createElement()定义的元素与使用JSX生成的元素相同,同样这就使得JSX天生就是需要编译的。

const element1 = (
  <h1 className="greeting">
    Hello,world!
  </h1>
);
// 等价
const element2 = React.createElement(
  'h1',{className: 'greeting'},'Hello,world!'
);

React.createElement()会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象。这些对象被称为React 元素,它们描述了你希望在屏幕上看到的内容,React通过读取这些对象,然后使用它们来构建DOM以及保持随时更新。

// 注意:这是简化过的结构
const element = {
  type: 'h1',props: {
    className: 'greeting',children: 'Hello,world!'
  }
};

实际上,这就是虚拟DOM的一个节点,Virtual DOM是一种编程概念,在这个概念里,UI以一种理想化的,或者说虚拟的表现形式被保存于内存中,并通过如ReactDOM等类库使之与真实的DOM同步,这一过程叫做协调。这种方式赋予了React声明式的API,您告诉React希望让UI是什么状态,React就确保DOM匹配该状态,这样可以从属性操作、事件处理和手动DOM更新这些在构建应用程序时必要的操作中解放出来。
与其将Virtual DOM视为一种技术,不如说它是一种模式,人们提到它时经常是要表达不同的东西。在React的世界里,术语Virtual DOM通常与React元素关联在一起,因为它们都是代表了用户界面的对象,而React也使用一个名为fibers的内部对象来存放组件树的附加信息,上述二者也被认为是ReactVirtual DOM 实现的一部分,Virtual DOM也为使用diff算法奠定了基础。

<div class="root" name="root">
    <p>1</p>
    <div>11</div>
</div>
// 使用Js对象去描述上述节点以及文档
{
    type: "tag",tagName: "div",attr: {
        className: "root"
        name: "root"
    },parent: null,children: [{
        type: "tag",tagName: "p",attr: {},parent: {} /* 父节点的引用 */,children: [{
            type: "text",tagName: "text",content: "1"
        }]
    },{
        type: "tag",content: "11"
        }]
    }]
}

示例

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>JSX示例</title>
</head>

<body>
  <div id="root"></div>
</body>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">

  class Clock extends React.Component {
    constructor(props) {
      super(props);
      this.state = { date: new Date() };
    }
    componentDidMount() {
      this.timer = setInterval(() => this.tick(),1000);
    }
    componentWillUnmount() {
      clearInterval(this.timer);
    }
    tick() {
      this.setState({ date: new Date() });
    }
    render() {
      return (
        <div>
          <h1>{this.props.tips}</h1>
          <h2>Now: {this.state.date.toLocaleTimeString()}</h2>
        </div>
      );
    }
  }

  class App extends React.Component{
    constructor(props){
      super(props);
      this.state = { 
        showClock: true,tips: "Hello World!"
      }
    }
    updateTips() {
      this.setState((state,props) => ({
        tips: "React update"
      }));
    }
    changeDisplayClock() {
      this.setState((state,props) => ({
        showClock: !this.state.showClock
      }));
    }
    render() {
      return (
        <div>
          {this.state.showClock && <Clock tips={this.state.tips} />}
          <button onClick={() => this.updateTips()}>更新tips</button>
          <button onClick={() => this.changeDisplayClock()}>改变显隐</button>
        </div>
      );
    }
  }

  var vm = ReactDOM.render(
    <App />,document.getElementById("root")
  );
</script>

</html>

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://www.zhihu.com/question/265784392
https://juejin.cn/post/6844904127013584904
https://zh-hans.reactjs.org/docs/introducing-jsx.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom