[React 基础系列] 什么是 JSX,以及如何使用 JSX

本文介绍了React库及其核心理念,重点讲解了JSX的使用,包括基本语法、嵌入表达式、函数调用、作为表达式及三元运算符的应用。同时,阐述了JSX如何提升代码可读性和效率,并展示了与原生JavaScript的对比。此外,还提到了JSX的属性、子组件和防止XSS攻击的安全特性。
摘要由CSDN通过智能技术生成

React 是由 facebook 开发、开源并维护的一个,而 React 的意义是在于使用 JavaScript 去实现用户交互——a JavaScript library for building user interfaces。

所以,本质上来说,React 是一个 ,而且它的作用是使用 JavaScript 去实现 用户交互

它的核心理念是用 JavaScript 去实现 HTML、CSS 和 JavaScript,通过组件化的概念实现单独的功能。

什么是 JSX

关于 JSX 的介绍,官网也有:Introducing JSX,并且也有中文翻译,有需求也可以到官网上看一下。尽管感觉像是机翻的

JSX 是 React 团队所提供的一个 JavaScript 语法扩展(以前也叫做语法糖)。它的写法和 HTML 有些相似,不过要注意,JSX 不是 HTML,不通过 babel 编译,直接使用 JSX,只会出现大量的语法错误。JSX 的最简单写法如下:

const element = <h1>Hello World</h1>;

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

渲染效果如下:

当然,我直接用 npx create-react-app app 创建了一个新的项目,这是重写了项目中的源码,才会有这样的效果——未经过 babel 编译的源码是无法直接在浏览器中运行的。

除此之外,JSX 也可以内嵌其他的变量,具体用法如下:

const name = 'John Wick';
const element = <h1>Hello, {name}</h1>;

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

效果如下:

使用 JSX 语法糖并不是必须的,也可以使用 JavaScript 直接进行编写,只不过这样的实现性和可读性都会低很多。下面是一组对比,原生的 JavaScript 是通过 babel 转译所获得:

  1. 只有 1 个 h1 标签

    使用 JSX 的实现如下:

    const element = <h1>Hello World</h1>;
    
    ReactDOM.render(element, document.getElementById('root'));
    

    使用原生 JavaScript 的实现如下:

    var element = /*#__PURE__*/ React.createElement('h1', null, 'Hello World');
    
    ReactDOM.render(element, document.getElementById('root'));
    
  2. 1 个变量 + 1 个 h1 标签

    使用 JSX 的实现如下:

    const name = 'John Wick';
    const element = <h1>Hello, {name}</h1>;
    
    ReactDOM.render(element, document.getElementById('root'));
    

    使用原生 JavaScript 的实现如下:

    var name = 'John Wick';
    var element = /*#__PURE__*/ React.createElement('h1', null, 'Hello, ', name);
    ReactDOM.render(element, document.getElementById('root'));
    
  3. 再嵌套一个组件

    使用 JSX 的实现如下:

    const username = 'John Wick';
    
    const element = (
      <h1>
        Hello, <span>{username}</span>
      </h1>
    );
    
    ReactDOM.render(element, document.getElementById('root'));
    

    使用原生 JavaScript 的实现如下:

    var username = 'John Wick';
    var element = /*#__PURE__*/ React.createElement(
      'h1',
      null,
      'Hello, ',
      /*#__PURE__*/ React.createElement('span', null, username)
    );
    ReactDOM.render(element, document.getElementById('root'));
    

可以看到,使用 JSX 编写的代码逻辑更加清晰,代码量也更少。再加上现在前端项目在进入生产环境之前总是要通过编译的,这也是为什么推荐使用 JSX 进行开发的原因。

下面就来看看 JSX 的具体用法。

表达式

JSX 本身的功能还挺强大的,从上面的例子中可以看到,JSX 可以嵌入一个表达式,同时,JSX 也可以作为作为一个表达式。

JSX 嵌入表达式

这就是案例 2 和案例 3 中的例子:

const name = 'John Wick';
const element = <h1>Hello, {name}</h1>;

可以看到,表达式/expression name 被嵌入到了 JSX 中。也因为这个特性,JSX 还能够嵌入他一些特殊的表达式。

在 JSX 使用函数

很多情况下,JSX 可以在 {} 体内进行简单的函数调用,例如说对数组的操作:

const fruits = [
  {
    id: 1,
    name: 'apple',
    price: 4,
  },
  {
    id: 2,
    name: 'banana',
    price: 2,
  },
];

const getFruitList = (fruits) => {
  return (
    <ul>
      {fruits.map((fruit) => (
        <li key={id}>
          <p>name: {fruit.name}</p>
          <p>price: {fruit.price}</p>
        </li>
      ))}
    </ul>
  );
};

const fruitList = getFruitList(fruits);

渲染后的结果如下:

JSX 作为表达式

同样,JSX 也可以作为一个值去被赋给对象,如:

const component = <ExampleComponent />;

ReactDOM.render(component, document.getElementById('root'));

这是一种比较常见的用法。

以三元表达返回 JSX

这也是一个比较常见的写法,有的时候会根据条件去判断是否返回一个组件的时候,就可以这么做:

const child = condition ? <ExampleComponent /> : null;

return (
  <SomeComponent>
    <OtherComponent />
    {child}
  </SomeComponent>
);

一般来说这种组件会被嵌入到其他的组件内去进行渲染。

JSX 与对象

JSX 的语法如此动态的原因,本质上是因为在经过编译之后,JSX 会被 babel 转化为一个对象。

如案例 1 所示:

const element = <h1>Hello World</h1>;
var element = /*#__PURE__*/ React.createElement('h1', null, 'Hello World');

两段代码本质上是一样的,createElement() 具体的内容不会过对赘述,但是它所做的就是返回一个对象。官网上有一个 createElement() 返回结果的简化版,大概就能知道它是接收一些参数,然后以对象的形式进行保存结果:

// Note: this structure is simplified
const element = {
  type: 'h1',
  // 对象的属性
  props: {
    // 类名,后面会解释
    className: 'greeting',
    // 子属性
    children: 'Hello, world!',
  },
};

属性

JSX 的属性分为两种,一种是原生的 HTML 就有的属性——注意为了防止关键字冲突,有些大小写会发生变化,另外一种就是自定义的属性,可以通过 props 在子组件中获取,完成父子组件的通信。

鉴于这里还没有完整的讲过组件的特性,所以会以基本的 HTML 属性为例:

const username = 'John Wick';

const element = (
  <h1 className="h1-heading">
    Hello, <span className="username">{username}</span> <br />
    <img
      src="https://img-blog.csdnimg.cn/20210706102601893.png"
      style={{ width: '350px' }}
    />
  </h1>
);

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

编译后的效果如下:

值得注意的一点就是,为了防止关键字冲突,HTML 中定义类名使用的是 class 关键字,在 JSX 中使用的是 className。通过这一点也可以看出来,在编写 React 代码过程中还是建议使用传统 JavaScript 的驼峰命名法。

:onClick,onChange 这些事件也可以作为属性传到 JSX 代码中去,这点会在之后讲组件的部分进行详解,这里只要知道就好。

另 2:样式,style 也可以作为属性,这种情工况下写出来的样式就是行内样式。

子组件

JSX 的嵌套就已经形成了父子组件,依旧以上面的代码为例:

const element = (
  <h1 className="h1-heading">
    Hello, <span className="username">{username}</span> <br />
    <img
      src="https://img-blog.csdnimg.cn/20210706102601893.png"
      style={{ width: '350px' }}
    />
  </h1>
);

在这个例子中,h1 就是父组件,而 img 和 span 就是子组件。注意,如果标签中没有额外的子组件,如 img 组件,那么就可以使用自闭合标签。

注入攻击

这也是年初的时候再次浏览官方文档的时候才发现的一个特性,原来 JSX 原生可以避免 XSS(cross-site-scripting) 攻击。XSS 指的是将恶意指令注入到 HTML 中,使得用户加载并且执行攻击的一种恶意程序。以下面的代码为例,如果这段代码作为用户输入的信息,而前端又没有进行任何的预防,那么该网站就会被攻击:

const userinput =
  "<a href='https://www.baibu.com' onClick={alert('attacked')}>超链接</a>";

如下面这里的 HTML 简单的实现了一个 input,然后会有另外一个节点渲染用户信息:

<input type="text" />
<div class="inputValue"></div>

<script>
  const input = document.querySelector('input');
  const inputValue = document.querySelector('.inputValue');
  input.addEventListener('change', () => {
    inputValue.innerHTML = input.value;
  });
</script>

当上面这段超链接代码被放入了输入框中后,页面就成了这样:

用户一旦点击 超链接,就会触发攻击:

JSX 会对代码进行转译,同样的代码放入 JSX 中,显示渲染的依旧是原本的代码:

const userinput =
  "<a href='https://www.baidu.com' onClick={alert('attacked')}>超链接</a>";

const element = <input type="text" value={userinput} />;
const inputValue = <div>{userinput}</div>;

ReactDOM.render(
  <Fragment>
    {element}
    {inputValue}
  </Fragment>,
  document.getElementById('root')
);

显示效果:

这是因为 JSX 会将所有输入的信息全都转译成字符串,再渲染到页面上,这就能够有效的避免 XSS 攻击。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值