JSX

作者: C_G__ | 来源:发表于2020-05-07 16:54 被阅读0次

    JSX是JavaScript的拓展语法,很像模板语言。

    
    const element = <h1>Hello, world!</h1>;
    
    //--------------------------------------------------------------------------------
    
    const name = 'Josh Perez';
    const element = <h1>Hello, {name}</h1>;
    ReactDOM.render(
      element,
      document.getElementById('root')
    );
    
    //--------------------------------------------------------------------------------
    
    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')
    );
    
    //--------------------------------------------------------------------------------
    
    function getGreeting(user) {
      if (user) {
        return <h1>Hello, {formatName(user)}!</h1>;  
      }
      return <h1>Hello, Stranger.</h1>;
    }
    const element = <div tabIndex="0"></div>;
    const element = <img src={user.avatarUrl}></img>;
    const element = (
      <div>
        <h1>Hello!</h1>
        <h2>Good to see you here.</h2>
      </div>
    );
    
    //--------------------------------------------------------------------------------
    
    // 防止注入攻击
    const title = response.potentiallyMaliciousInput;
    // 直接使用是安全的:
    const element = <h1>{title}</h1>;
    
    //--------------------------------------------------------------------------------
    // 2种写法
    const element = (
      <h1 className="greeting">
        Hello, world!
      </h1>
    );
    const element = React.createElement(
      'h1',
      {className: 'greeting'},
      'Hello, world!'
    );
    

    组件

    // 函数组件
    function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }
    // class组件
    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    const element = <Welcome name="Sara" />;
    ReactDOM.render(
      element,
      document.getElementById('root')
    );
    

    注意: 组件名称必须以大写字母开头。
    React 会将以小写字母开头的组件视为原生 DOM 标签。例如,<div /> 代表 HTML 的 div 标签,而 <Welcome /> 则代表一个组件,并且需在作用域内使用 Welcome。

    提取组件
    原组件

    function Comment(props) {
      return (
        <div className="Comment">
          <div className="UserInfo">
            <img className="Avatar"
              src={props.author.avatarUrl}
              alt={props.author.name}
            />
            <div className="UserInfo-name">
              {props.author.name}
            </div>
          </div>
          <div className="Comment-text">
            {props.text}
          </div>
          <div className="Comment-date">
            {formatDate(props.date)}
          </div>
        </div>
      );
    }
    

    提取后

    function Avatar(props) {
      return (
        <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} />  
      );
    }
    function UserInfo(props) {
      return (
        <div className="UserInfo">      
          <Avatar user={props.user} />      
          <div className="UserInfo-name">{props.user.name}</div>    
        </div>
      );
    }
    function Comment(props) {
      return (
        <div className="Comment">
          <UserInfo user={props.author} />      
          <div className="Comment-text">
            {props.text}
          </div>
          <div className="Comment-date">
            {formatDate(props.date)}
          </div>
        </div>
      );
    }
    

    Props 的只读性
    所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

    生命周期

    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
      // 挂载
      componentDidMount() { 
        this.timerID = setInterval(()=>this.tick(), 1000);
      }
      // 卸载
      componentWillUnmount() { 
        clearInterval(this.timerID);
      }
      tick() {    
        this.setState({date: new Date()});  
      }
      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }
    ReactDOM.render(
      <Clock />,
      document.getElementById('root')
    );
    
    1. 当 <Clock /> 被传给 ReactDOM.render()的时候,React 会调用 Clock 组件的构造函数。因为 Clock 需要显示当前的时间,所以它会用一个包含当前时间的对象来初始化 this.state。我们会在之后更新 state。
    2. 之后 React 会调用组件的 render() 方法。这就是 React 确定该在页面上展示什么的方式。然后 React 更新 DOM 来匹配 Clock 渲染的输出。
    3. 当 Clock 的输出被插入到 DOM 中后,React 就会调用 ComponentDidMount() 生命周期方法。在这个方法中,Clock 组件向浏览器请求设置一个计时器来每秒调用一次组件的 tick() 方法。
    4. 浏览器每秒都会调用一次 tick() 方法。 在这方法之中,Clock 组件会通过调用 setState() 来计划进行一次 UI 更新。得益于 setState() 的调用,React 能够知道 state 已经改变了,然后会重新调用 render() 方法来确定页面上该显示什么。这一次,render() 方法中的 this.state.date 就不一样了,如此以来就会渲染输出更新过的时间。React 也会相应的更新 DOM。
    5. 一旦 Clock 组件从 DOM 中被移除,React 就会调用 componentWillUnmount() 生命周期方法,这样计时器就停止了。

    不要直接修改 State

    // 错误做法
    this.state.comment = 'Hello';
    // 正确做法
    this.setState({comment: 'Hello'});
    

    State 的更新可能是异步的
    出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。

    // 错误做法
    this.setState({
      counter: this.state.counter + this.props.increment,
    });
    // 正确做法
    this.setState((state, props) => ({
      counter: state.counter + props.increment
    }));
    // 正确做法
    this.setState(function(state, props) {
      return {
        counter: state.counter + props.increment
      };
    });
    

    事件处理

    // html
    <button onclick="activateLasers()"> Activate Lasers </button>
    // react
    <button onClick={activateLasers}> Activate Lasers </button>
    
    function ActionLink() {
      function handleClick(e) {    
        e.preventDefault();    
        console.log('The link was clicked.'); 
      }
      return (
        <a href="#" onClick={handleClick}>Click me</a>
      );
    }
    
    class Toggle extends React.Component {
      constructor(props) {
        super(props);
        this.state = {isToggleOn: true};
        // 为了在回调中使用 `this`,这个绑定是必不可少的    
        this.handleClick = this.handleClick.bind(this);  
    }
    handleClick() {    
      this.setState(state => ({  isToggleOn: !state.isToggleOn   }));  
    }
    render() {
        return (
          <button onClick={this.handleClick}>{this.state.isToggleOn ? 'ON' : 'OFF'}</button>
        );
      }
    }
    
    ReactDOM.render(
      <Toggle />,
      document.getElementById('root')
    );
    

    条件渲染

    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')
    );
    
    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>  
      );
    }
    

    阻止组件渲染
    return null

    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(state => ({
          showWarning: !state.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')
    );
    

    列表 & Key

    const numbers = [1, 2, 3, 4, 5];
    const doubled = numbers.map((number) => number * 2);
    console.log(doubled);
    
    const numbers = [1, 2, 3, 4, 5];
    const listItems = numbers.map((number) => <li>{number}</li>);
    ReactDOM.render(
      <ul>{listItems}</ul>
    , document.getElementById('root')
    );
    
    // 基础列表组件 
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) => 
        <li key={number.toString()}>{number}</li>
      );  
      return (
        <ul>{listItems}</ul>  
      );
    }
    const numbers = [1, 2, 3, 4, 5];
    ReactDOM.render(
      <NumberList numbers={numbers} />
    , document.getElementById('root')
    );
    
    
    function ListItem(props) {
      // 正确!这里不需要指定 key:  
      return <li>{props.value}</li>;
    }
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        // 正确!key 应该在数组的上下文中被指定    
        <ListItem key={number.toString()} value={number} />
      );
      return (
        <ul>{listItems}</ul>
      );
    }
    const numbers = [1, 2, 3, 4, 5];
    ReactDOM.render(
      <NumberList numbers={numbers} />
    , document.getElementById('root')
    );
    

    key 只是在兄弟节点之间必须唯一

    function Blog(props) {
      const sidebar = (    
        <ul>
          {props.posts.map((post) =>
            <li key={post.id}>{post.title}</li>
          )}
        </ul>
      );
      const content = props.posts.map((post) =>    
        <div key={post.id}>      
          <h3>{post.title}</h3>
          <p>{post.content}</p>
        </div>
      );
      return (
        <div>
          {sidebar}      
          <hr />
          {content}    
        </div>
      );
    }
    const posts = [
      {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
      {id: 2, title: 'Installation', content: 'You can install React from npm.'}
    ];
    ReactDOM.render(
      <Blog posts={posts} />,
      document.getElementById('root')
    );
    

    在 JSX 中嵌入 map()

    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>    
        <ListItem key={number.toString()} value={number} />  
      );  
      return (
        <ul>{listItems}</ul>
      );
    }
    // JSX 允许在大括号中嵌入任何表达式
    function NumberList(props) {
      const numbers = props.numbers;
      return (
        <ul>
          {numbers.map((number) => 
            <ListItem key={number.toString()} value={number} />)}
        </ul>
      );
    }
    

    表单

    <form>
      <label>
        名字:
        <input type="text" name="name" />
      </label>
      <input type="submit" value="提交" />
    </form>
    

    **受控组件 **

    相关文章

      网友评论

          本文标题:JSX

          本文链接:https://www.haomeiwen.com/subject/tqpwghtx.html