美文网首页React学习笔记
React进阶笔记1(jsx深入理解)

React进阶笔记1(jsx深入理解)

作者: XKolento | 来源:发表于2018-08-02 16:37 被阅读0次

    深入jsx

    从本质上来说,jsx只是为React.creatElement(component,props)提供的语法糖。例如:

    <Mybutton color="blue" shadowsize={2}>
        click me
    </Mybutton>
    

    编译后得到(也就是React底层实现的过程):

    React.createElement(
        Mybutton,//组件名
        {color:"blue",shadowsize:2},//相关属性
        "click me" //文本内容
    )
    

    如果节点中没有子代。子节点,还可以直接使用自闭和标签。如:

    <div className="sidebar" />
    

    然后编译为:

    React.createElement(
        'div',
        {className:"sidebar"},
        null
    )
    

    如果你想彻底验证 JSX 是如何转换为 JavaScript 的,你可以尝试 在线 Babel 编译器.

    指定React元素类型

    jsx的标签名决定了React的元素类型。

    大写开头的jsx标签表示一个React组件。这些标签会被编译成同名的变量然后引用。如果你使用<Kolento />,就必须在作用域中生命Kolento变量。

    React必须声明

    由于jsx在编译后会调用React.createElement()方法,所以你的jsx中必须首先声明React变量,否则就找不到React了。

    例如:下面的声明都是必须的。
    尽管React和CustomButton都没有被直接调用。

    import React from 'react';
    import CustomButton from './CustomButton';
    function WarningButton(){
    // 返回 React.createElement(CustomButton, {color: 'blue'}, null);
        return <CustomButton color="blue" />
    }
    

    如果使用script加载React,他会作用于全局

    点表示法

    我们还可以使用React中的点表示法来引用React组件。你可以方便的从一个模块中,导出许多React组件,有一个叫Components.DatePicker的组件。可以直接在jsx中使用它。
    调用的时候只要Components.DatePicker 即可

    const MyComponents = {
        DatePicker:function Date(props){
            return <div>Imagine a {props.color} datepicker here</div>    
        }
    }
    
    function BlueDatePicker(){
        return <MyComponents.DatePicker color="blue" />
    }
    

    首字母大写

    当元素的首字母以小写开头,则表示他是一个内置的组件,如div span,并将字符串 ‘div’ 或 ‘span’ 传 递给 React.createElement。 以大写字母开头的类型,如 <Foo /> 编译为 React.createElement(Foo),并它正对应于你在 JavaScript 文件中定义或导入的组件。

    我们建议用大写开头命名组件。如果你的组件以小写字母开头,请在 JSX 中使用之前其赋值给大写开头的变量。

    错误demo
    import React from 'react';
    
    // 错误!组件名应该首字母大写:
    function hello(props) {
      // 正确!div 是有效的 HTML 标签:
      return <div>Hello {props.toWhat}</div>;
    }
    
    function HelloWorld() {
      // 错误!React 会将小写开头的标签名认为是 HTML 原生标签:
      return <hello toWhat="World" />;
    }
    

    为了解决这个问题,我们将 hello 重命名为 Hello,然后使用 <Hello /> 引用:

    import React from 'react';
    
    // 正确!组件名应该首字母大写:
    function Hello(props) {
      // 正确!div 是有效的 HTML 标签:
      return <div>Hello {props.toWhat}</div>;
    }
    
    function HelloWorld() {
      // 正确!React 能够将大写开头的标签名认为是 React 组件。
      return <Hello toWhat="World" />;
    }
    

    在运行时选择类型

    我们不能使用表达式来作为React的标签,如果想用表达式的方式确定React的元素类型,要将表达式赋值给一个大写开头的标量,这种情况一般会在条件渲染的时候出现。

    import React from 'react';
    import { PhotoStory, VideoStory } from './stories';
    
    const components = {
      photo: PhotoStory,
      video: VideoStory
    };
    
    function Story(props) {
      // 错误!JSX 标签名不能为一个表达式。
      return <components[props.storyType] story={props.story} />;
    }
    

    以上demo 使用表达式去输出一个标签,这是不可行的,需要将components[props.storyType]赋值给一个大写开头的变量替换进去才行。

    解决:要解决这个问题,我们需要先将类型赋值给大写开头的变量。

    import React from 'react';
    import { PhotoStory, VideoStory } from './stories';
    
    const components = {
      photo: PhotoStory,
      video: VideoStory
    };
    
    function Story(props) {
      // 正确!JSX 标签名可以为大写开头的变量。
      const SpecificStory = components[props.storyType];
      return <SpecificStory story={props.story} />;
    }
    

    属性

    在jsx中有几种不同的方式来指定属性

    使用js表达式

    可以传递任何{}包裹的javascript表达式作为一个属性值。

    <MyComponent foo={1 + 2 + 3 + 4} />
    

    对于MyComponent来说,props.foo的值为10,是通过表达式1+2+3+4计算出来的。

    if语句和for循环在js中不是表达式,因此不能再jsx中直接引用。但是可以将它放在周围的代码中。

    function NumberDescriber(props) {
      let description;
      if (props.number % 2 == 0) {
        description = <strong>even</strong>;
      } else {
        description = <i>odd</i>;
      }
      return <div>{props.number} is an {description} number</div>;
    }
    

    你可以在相关部分中了解有关 条件渲染循环 的更多信息。

    字符串常量

    可以将字符串常量作为属性传递,以下的2个jsx是等价的。

    <MyComponents message={"hello"} />
    <MyComponents message="hello" />
    

    当传递一个字符串常量时,该值会被解析为HTML非转义字符串,所以下面两个 JSX 表达式是相同的:

    <MyComponent message="&lt;3" />
    <MyComponent message={'<3'} />
    

    以上的这点,了解一下即可。

    属性默认为true

    如果你没有给属性传值,则他默认为true,因此一下2个jsx表达式是等价的。

    <MyTextBox autocomplete />
    <MyTextBox autocomplete={true} />
    

    一般情况下,我们不建议这样使用,因为它会与 ES6 对象简洁表示法 混淆。比如 {foo}{foo: foo} 的简写,而不是 {foo: true}。这里能这样用,是因为它符合 HTML 的做法。

    扩展属性

    如果你已经有了props对象,并且想在jsx中传递他,可以使用...作为扩展操作符来传递整个对象。以下的2个组件是等价的。

    function App1() {
      return <Greeting firstName="Ben" lastName="Hector" />;
    }
    
    function App2(){
      const props = {firstName:"Ben",lastName="Hector"}
      return <Greeting {...props}>
    }
    

    当你构建通用容器时,扩展属性会非常有用。然而,这样做也可能让很多不相关的属性,传递到不需要它们的组件中使代码变得混乱。我们建议你谨慎使用此语法。

    子代

    在包含开始与结束标签之间的jsx表达式中,标记之间的内容可以作为特殊的参数传递props.children,有几种不同的方法来传递子代。
    也就是说props.children指代标签中的内容。

    字符串常量

    你可以在开始和结束标签之间放入一个字符串,则 props.children就是那个字符串。这对于许多内置 HTML 元素很有用。例如:

    <MyComponent>hello world</MyComponent>
    

    这是有效的 JSX,并且 MyComponent 的 props.children 值将会直接是 "hello world!"。因为 HTML 未转义,所以你可以像写 HTML 一样写 JSX:

    <div>This is valid HTML &amp; JSX at the same time.</div>
    

    JSX 会移除空行和开始与结尾处的空格。标签邻近的新行也会被移除,字符串常量内部的换行会被压缩成一个空格,所以下面这些都等价:

    <div>Hello World</div>
    
    <div>
      Hello World
    </div>
    
    <div>
      Hello
      World
    </div>
    
    <div>
    
      Hello World
    </div>
    

    jsx

    可以通过子代镶嵌嵌套更多的jsx元素,这对于镶嵌组件非常有用。

    <MyContainer>
      <MyFirstComponent />
      <MySecondComponent />
    </MyContainer>
    

    其中可以混合不同类型的子元素,同时用字符串常量和jsx子元素,这是jsx类似html的另一种形式,这在jsx和html中都是有效的。

    <div>
      Here is a list:
      <ul>
        <li>Item 1</li>
        <li>Item 2</li>
      </ul>
    </div>
    

    React组件也可以通过数组的形式返回多个元素

    render() {
      // 不需要使用额外的元素包裹数组中的元素
      return [
        // 不要忘记 key :)
        <li key="A">First item</li>,
        <li key="B">Second item</li>,
        <li key="C">Third item</li>,
      ];
    }
    

    js表达式

    可以将任何{}包裹的js表达式作为子代传递,比如,以下的表达式是等价的。

    <MyComponent>foo</MyComponent>
    <MyComponent>{'foo'}</MyComponent>
    

    这对于渲染任意长度的jsx表达式都很有用。下面将会渲染一个HTML列表。

    function Item(props){
        return <li>{props.message}</li>
    }
    
    function TodoList(){
        const todos=[
            'first','second','third'
        ]
        return(
            <ul>
                {todos.map(message=><Item key={message} message={message} />)}
            </ul>
        )
    }
    
    ReactDOM.render(
        <TodoList />,document.getElementById('root')
    )
    

    js表达式可以与其他类型的子代混合使用。这通常对于字符串模板非常有用。

    function Hello(props) {
      return <div>Hello {props.addressee}!</div>;
    }
    

    函数

    在通常情况下,插入jsx中的js表达式被认为是字符串、React元素或者这些内容的列表。然而props.children可以向其他属性一样传递任何的数据,而不仅仅是React元素。

    如果你调用自定义组件,就可以使用props.children来获取进行传递。

    // Calls the children callback numTimes to produce a repeated component
    function Repeat(props) {
      let items = [];
      for (let i = 0; i < props.numTimes; i++) {
        items.push(props.children(i));
      }
      return <div>{items}</div>;
    }
    
    function ListOfTenThings() {
      return (
        <Repeat numTimes={10}>
          {(index) => <div key={index}>This is item {index} in the list</div>}
        </Repeat>
      );
    }
    

    递给自定义组件的子代可以是任何元素,只要该组件在 React 渲染前将其转换成 React 能够理解的东西。这个用法并不常见,但当你想扩展 JSX 时可以使用。

    布尔值、Null 和 Undefined 被忽略

    false、null、undefined 和 true 都是有效的子代,但它们不会直接被渲染。下面的表达式是等价的:

    <div />
    
    <div></div>
    
    <div>{false}</div>
    
    <div>{null}</div>
    
    <div>{undefined}</div>
    
    <div>{true}</div>
    

    这在根据条件来确定是否渲染React元素时非常有用。以下的JSX只会在showHeader为true时渲染<Header />组件。

    <div>
      {showHeader && <Header />}
      <Content />
    </div>
    

    相反,如果你想让类似 falsetruenullundefined 出现在输出中,你必须先把它转换成字符串 :

    <div>
      My JavaScript variable is {String(myVariable)}.
    </div>
    

    相关文章

      网友评论

        本文标题:React进阶笔记1(jsx深入理解)

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