【React教程】(2) React之JSX入门与列表渲染、条件渲染详细代码示例-LMLPHP

JSX

HTML 语言直接写在 JavaScript 语言中,不加任何引号,这就是 JSX 语法。它允许 HTML 与 JavaScript 的混写。

环境配置

  • 非模块化环境
    • babel-standalone
  • 模块化环境
    • babel-preset-react
  • Babel REPL 赋值查看编译结果

基本语法规则

  • 必须只能有一个根节点

  • 遇到 HTML 标签 (以 < 开头) 就用 HTML 规则解析

    • 单标签不能省略结束标签。
  • 遇到代码块(以 { 开头),就用 JavaScript 规则解析

  • JSX 允许直接在模板中插入一个 JavaScript 变量

    • 如果这个变量是一个数组,则会展开这个数组的所有成员添加到模板中
  • 单标签必须结束 />

基本语法:

const element = <h1>Hello, world!</h1>;

在 JSX 中嵌入 JavaScript 表达式

  • 语法
  • 如果 JSX 写到了多行中,则建议包装括号避免自动分号的陷阱
function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);

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

在 JavaScript 表达式中嵌入 JSX

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

JSX 中的节点属性

  • 动态绑定属性值
  • class 使用 className
  • tabindex 使用 tabIndex
  • for 使用 htmlFor

普通的属性:

const element = <div tabIndex="0"></div>;

在属性中使用表达式:

const element = <img src={user.avatarUrl}></img>;

声明子节点

如果标签是空的,可以使用 /> 立即关闭它。

const element = <img src={user.avatarUrl} />;

JSX 子节点可以包含子节点:

const element = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);

JSX 自动阻止注入攻击

const element = <div>{'<h1>this is safe</h1>'}</div>

在 JSX 中使用注释

写法一:

{
  // 注释
  // ...
}

写法二(单行推荐):

{/* 单行注释 */}

写法三(多行推荐):

{
  /*
   * 多行注释
   */
}

JSX 原理

Babel 会把 JSX 编译为 React.createElement() 函数。

  • 每个 React 元素都是一个真实的 JavaScript 对象

下面两种方式是等价的:

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
// Note: this structure is simplified
const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world'
  }
};

列表循环

JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员。

var arr = [
  <h1>Hello world!</h1>,
  <h2>React is awesome</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

综上所述,我们可以这样:

var names = ['Alice', 'Emily', 'Kate'];

ReactDOM.render(
  <div>
  {
    names.map(function (name) {
      return <div>Hello, {name}!</div>
    })
  }
  </div>,
  document.getElementById('example')
);

DOM Elements

列表渲染

语法高亮

条件渲染

示例1:

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

ReactDOM.render(
  // Try changing to isLoggedIn={true}:
  <Greeting isLoggedIn={false} />,
  document.getElementById('root')
);

示例2:

function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}

function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;

    let button = null;
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }

    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);

示例3(行内判断):

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
);

示例4(if-else):

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}
render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}

示例5(阻止组件渲染):

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    <div className="warning">
      Warning!
    </div>
  );
}

class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = {showWarning: true}
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }

  handleToggleClick() {
    this.setState(prevState => ({
      showWarning: !prevState.showWarning
    }));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? 'Hide' : 'Show'}
        </button>
      </div>
    );
  }
}

ReactDOM.render(
  <Page />,
  document.getElementById('root')
);
01-30 09:02