React 学习笔记(5)—— JSX

178 阅读2分钟

JSX 就是 React.createElement(component, props, ...children) 函数的语法糖。

指定 React 元素类型 component

  1. 由于 JSX 会编译为函数 React.createElement 的调用,因此 React 库和 React 组件所在作用域必须位于 JSX 的作用域链上。

  2. JSX 中可以使用点语法来引用 React 组件,这可以方便地从一个模块中导出多个 React 组件。

  3. JSX 中,小写字母开头的元素代表 HTML 内置组件,最终会编译为字符串传给 React.createElement 的第一个参数;大写字母开头的元素代表自定义 React 组件,最终会编译为命名变量的直接引用传给 React.createElement 的第一个参数。React 建议使用大写字母开头命名自定义组件,或者在 JSX 使用自定义组件之前,将其赋值给一个大写字母开头的变量。

  4. 通用 JavaScript 表达式无法作为 React 元素类型。如果想用通用表达式来动态决定元素类型,可以在 JSX 使用它之前将其赋值给一个大写字母开头的变量。这通常用于根据 prop 来渲染不同组件的情形。

import React from "react";
import CustomButton from "./CustomButton";

const MyComponents = {
  CustomButton,
};

const MyButtons = {
  warning: function WarningButton() {
    // React.createElement(MyComponents.CustomButton, {color: "yellow"}, null);
    return <MyComponents.CustomButton color="yellow" />;
  },
  error: function ErrorButton() {
    return <MyComponents.CustomButton color="red" />;
  },
};

function Buttons(props) {
  const SpecificButton = MyButtons[props.buttonType];
  
  // React.createElement('div', null, React.createElement(SpecificButton), React.createElement(SpecificButton));
  return (
    <div>
      <SpecificButton />
      <SpecificButton />
    </div>
  );
}

指定属性 props

  1. JavaScript 表达式

    iffor 语句不是表达式,不能直接传给 prop,但是可用于条件渲染或创建列表。

  2. 字符串字面量

    字符串字面量赋值给 prop 时,它的值是未转义的。

  3. 没有值的 prop 默认值为 true

    为避免与 ES6 对象简写混淆,React 不建议没有 value 的 prop。

  4. 属性展开

    使用展开运算符可以将整个对象传给 React 元素的 props。属性展开在某些情况下很有用,但是也很容易把不必要的 props 传给不相关的组件,或者将无效的 HTML 属性传递给 DOM,React 建议慎用这种语法。

import React from "react";
import Tooltip from "./Tooltip";
import MyTextBox from "./MyTextBox";

function Example(props) {
  const defaultProps = {
    text: "MyTextBox",
    autocomplete: true,
  };

  return (
    <Tooltip title={`box ${props.id}`}>
      <MyTextBox text="MyTextBox" autocomplete />
      <MyTextBox {...defaultProps} />
    </Tooltip>
  );
}

指定子元素 children

包含在开始和结束标签之间的 JSX 表达式内容,将传递给外层组件特定属性 props.children

  1. 字符串字面量

    开始和结束标签之间只有一个字符串,那么 props.children 就是该未转义字符串,这对于内置的 HTML 标签很有用。JSX 会移除行首尾的空格以及空行,与标签相邻的空行直接删除,文本字符串之间的空行会被压缩为一个空格。

  2. JSX

    子元素可以是一个或多个 JSX 元素,也可以将不同类型的子元素混合起来。React 组件允许返回由 JSX 元素所构成的数组。

  3. JavaScript 表达式

    JavaScript 表达式包裹在 {} 中作为子元素,这对于展示任意长度的列表很有用。JavaScript 表达式也可以和其它类型子元素结合起来使用,这种做法可以方便地替代模板字符串。

  4. 函数

    JSX 中的 JavaScript 表达式会被计算为相应的值,如:字符串、列表、React 元素等。props.children 和其它 prop 一样,可以接收任何类型的数据,如:函数,而不必是已知的 React 可渲染类型,只要确保该组件渲染前能被转换为 React 理解的对象即可。这种做法不常见,但可以扩展 JSX。

  5. 布尔类型、nullundefined 不会被渲染

    nullundefinedtruefalse 是合法的子元素,但不会被渲染,这有助于依据特定条件来渲染其它 React 元素。其它类型的数据,即使 truthiness 为 false,也会被渲染。

import React from "react";
import MyElement from "./MyElement";
import Item from "./Item";
import Content from "./Content";
import Header from "./Header";

function Example(props) {
  const toDos = ["finish doc", "submit pr"];
  return props.type !== "array" ? (
    <div>
      Hello World
      <MyElement>{"foo"} bar</MyElement>
      <div>
        {toDos.map((item) => (
          <Item key={item} message={item} />
        ))}
      </div>
    </div>
  ) : (
    [<li key={"a"}>A</li>, <li key={"b"}>B</li>]
  );
}

function List(props) {
  return (
    <div>
      {new Array(props.nums).map((num) => {
        return props.children(num);
      })}
    </div>
  );
}

function FnTest() {
  return <List nums={10}>{(num) => <div key={num}>item {num}</div>}</List>;
}

function Test(props) {
  return (
    <div>
      {props.showHeader && <Header />}
      <Content />
    </div>
  );
}

不使用 JSX

React 不强制使用 JSX,如果不想在构建环境中配置有关 JSX 的编译,可以直接使用 React.createElement(component, props, ...children) 函数。该函数的第一个参数 component 可以是字符串、React.Component 的子类、函数。

React.createElement 函数创建快捷方式,可以更加方便地使用无 JSX 的 React。

import React from "react";
import ReactDOM from "react-dom/client";

const h = React.createElement;

class Hello extends React.Component {
  render() {
    return h("div", null, `Hello ${this.props.name}`);
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(h(Hello, { name: "React.createElement" }, null));