React学习(3)-不可不知的JSX

前言

react学习(3)-不可不知的JSX.png

本篇内容,对上一节的补充

  1. JSX中添加属性有什么要注意的?以及JSX中的子元素是怎么操作的?

  2. 组件的大小写问题,使用拓展运算符,以及怎么循坏遍历一个对象

  3. JSX中的prop指的是什么?以及表单的labe应该要注意什么?

以上问题即使自己很清楚,但是否有时却总是道不清,说不明?那么读完本文,就豁然开朗了

JSX添加特定属性

自定义标签拓展了原生HTML标签不具备的能力,最大的一个用处就是属性传值,标签的属性值,可以是字符串,变量对象

例如:如下所示

const element = <div divIndex ="0"></div>

当然也可以使用下面这种方式,是等价的,用一个大括号将变量包裹起来

const element = <div divIndex={"0"}></div>

至于更多插值表达式内容,你可以看上一节的

这里要提一下,在属性中嵌入javascript表达式,不要在双大括号外面加上引号,例如,下面的是错误的

const element = <div divIndex="{ variable }"></div>

也就是说,对于字符串或者双大括号中的表达式,对于同一属性,不能同时使用这两种符号

注意

JSX语法是更接近Javascript而不是HTML,只是长得像而已,对于Reat中自定义组件的属性名称,使用camelCase驼峰式命名来定义属性的名称,例如:定义JSX里的class属性,classNamed而divindex变成divIndex

JSX中的子元素

在原生HTML标签中,要是对于DOM结构树熟悉的话,理解JSX的子元素也是比较容易的

原生HTML的标签叫做节点,节点有节点属性,以及节点的内容

如果一个标签或者React组件没有内容,你是可以使用/>,单标签来闭合的,就像XML语法一样,例如如下所示

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

JSX标签里面能够包含很多个子元素

例如:如下所示

const element = (
    <div>
        <h1 title="我是子h1元素属性的内容">我是子h1元素的节点内容</h1>
        <h2>欢迎关注微信itclanCoder公众号</h2>
        <h3>川川是全宇宙最帅的小伙子</h3>
    </div>
)

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

其中,有下面几种不同的方法来传递子元素

字符串字面量

你可以将字符串放在开始和结束标签之间,此时props.children就只是该字符串,对于内置的HTML元素是很有用的,但同时要注意怎么接收这个内容

<MyComponent>itclanCoder</MyComponent>

上面的JSX,MyComponent的子元素内容是itclanCoder,可以通过props.children来获取,它是一个没有转移的字符串itclanCoder

JSX会移除首尾行以及空行,与标签相邻的空行都会被删除,文本字符串之间的新航都会被压缩一个空格

所以下面的这几种写法都是等价的

<div>itclanCoder</div>

<div>
  itclanCoder
</div>

<div>
  川川
  itclanCoder
</div>

<div>

  itclanCoder
</div>

JSX子元素嵌套

在React中,子元素允许由多个JSX元素组成,组件可以嵌套组件,例如:如下所示

<MyContainer>
   <Header />
   <Navigator />
   <Aside />
   <Footer />
</MyContainer>

在React中,是可以将不同类型的子元素混合在一起的,这跟在以前写HTML是一样的

<div>
   七月的天好热
   <ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
   </ul>
</div>

在React组件中,render函数的return的返回值,可以返回一个数组,例如:

render() {
    // return 后面是一个数组
    return [
      <div key="div1">div1</div>,
      <div key="div2">div2</div>,
      <div key='div3'>div3</div>
    ]
}
// 当然为了更好的看得舒服些的,最好是定义一个变量的
render() {
    var aDiv = [
        <div key="div1">div1</div>,
      <div key="div2">div2</div>,
      <div key='div3'>div3</div>
    ]
    return aDiv;
}

javascript表达式作为子元素

在插值表达式中,javascript表达式可以被包裹在双大括号{}中,以下两种写法都是等价的

<myComponent>川川</myComponent>
<myComponent>{'川川'}</myComponent>

至于这种写法的具体实用:对于展示任意长度的列表就非常有用了的,渲染HTML列表


import React from 'react';  
import ReactDOM from 'react-dom';


class Item extends React.Component {
    constructor(props) {
        super(props);


    }

    render() {
        return (
           <ul>
               <li>{ this.props.message }</li>
           </ul>
        );
    }
}

class TodoLIst extends React.Component {
    constructor(props) {
        super(props);

        this.todos = ['起床', '刷牙', '洗脸', '工作'];
    }

    render() {
        return (
            <div>
                {
                    this.todos.map((message) => <Item key = {message} message = { message } />)
                }
            </div>
        );
    }
}

const container = document.getElementById('root');

ReactDOM.render(<TodoLIst />, container);

效果如下所示


javascript表达式作为子元素.png

函数作为子元素

{}插值表达式内可以可以变量,字符串,普通HTML元素,甚至可以是组件,还可以是函数

import React from 'react';      // 引入react.js,通过import关键字实例化一个React对象
import ReactDOM from 'react-dom'; 
import { tsPropertySignature } from '@babel/types';

function Repeat(props){
    let items = [];
    for(let i = 0; i < props.numTimes; i++) {
        items.push(props.children(i));
    }

    return <div>{ items }</div>
}

function ListOfTenFun() {
    return (
        <Repeat numTimes={ 10 }>
            {
                (index) => <div key={index}>我是列表 { index }</div>
            }
        </Repeat>
    )
}


const container = document.getElementById('root');

ReactDOM.render(<ListOfTenFun />, container);

效果如下所示:


函数作为子元素列表.png

上面使用的是两个函数组件,组件里面是可以嵌套另一组件的,并且属性值可以通过props拿到

也说明了,你是可以将任何东西作为子元素传递给自定义的组件的,
只要该组件渲染之前能够被转换成React理解的对象,它可以用于拓展JSX

自定义的组件必须是大写字母开头

通常来说,如果在React中小写字母开头的html标签,称为普通元素,它是原生HTML内置的元素(也可以视为为组件),例如:<div>``<span>``<a>会被React转化生成相应的字符串'div','span'传递给React.createElement作为参数

大写字母开头的元素,我们将它视为自定义的组件,例如<MyButton />,其实它最终也会被React.createElement函数作为转化

使用大写字母开头命名自定义组件,这是一种约定俗成的规定,本质上它就是一构造函数,是为了区别普通函数的

JSX标签的第一部分指定了React元素的类型

凡是大写字母开头的JSX标签元素,就意味着它们是React组件

如果你定义的一个组件首字母是小写,react就会当做一个普通元素来处理,而原生HTML标签并没有把你自定义的元素归纳进去,它是会报错的

例如:如下所示

import React from 'react';    
import ReactDOM from 'react-dom'; 
import { tsPropertySignature } from '@babel/types';

// 以下是定义的函数组件,首字母小写,这个是不正确的
function button(props) {
    return (
        <div>
            <button>{ props.content }</button>
        </div>
    )
}

function OutButton(){
    return (
        <Button content="按钮" />
    );
}

const container = document.getElementById('root');

ReactDOM.render(<OutButton />, container);

// 正确的写法
function Button(props) {
    return (
        <div>
            <button>{ props.content }</button>
        </div>
    )
}



ReactDOM.render(<OutButton />, container);

虽然错误的写法不会报错,它会将button认为是一个html普通的标签元素.

注意:

React必须在作用域内,JSX其实就是React.createElement函数的语法糖,React.createElement是更接近底层的API,所以React库也必须包含在JSX代码作用域内

引入React库一部分目的就是为了识别JSX语法的,这也是为什么只要你定义一个React组件时,要引入React库的原因

使用点(.)语法

有时候,在一个模块中需要导出多个React组件时,在JSX中,使用点语法来引用一个React组件就非常方便了的
例如:如下所示

import React, { Fragment, Component } from 'react';      
import ReactDOM from 'react-dom'; 


// MyButton组件
class MyButton extends Component {
   constructor(props){
      super(props);
   }

    render() {
        return (
            <Fragment>
                <button>{ this.props.btnContent }</button>
            </Fragment>
        );
    }
}

// MyInput组件
class MyInput extends Component{
    constructor(props) {
        super(props);

    }


    render() {
        return (
           <Fragment>
                <input value = { this.props.inputValue }  />
           </Fragment>
        );
    }
}

// 搜索部分
class SearchArea extends Component {

    render() {
        return (
           <Fragment>
                 <FormComponent.MyInput  inputValue="我是input组件输入框内容" />
                 <FormComponent.MyButton btnContent="搜索按钮" />
           </Fragment>
        );
    }
}

let FormComponent = {
    MyButton: MyButton,
    MyInput: MyInput
}
// 或者下面是Es6的一种等价写法
let FormComponent = {
    MyButton,
    MyInput
}

const container = document.getElementById('root');

ReactDOM.render(<SearchArea />, container);

最终结果如下图所示:


搜索按钮.png

上面是把页面中的某一个模块(搜索),把与之相关的组件集中放在一个对象下管理,当然在实际开发中,因人而异了,要是看到别人这么写,也不要觉得怪怪的.

拓展运算符,属性展开

对于拓展运算符(...),是一个非常有用的语法,如果你已经有了一个props对象,你可以使用展开运算符...在JSX中传递整个props对象
如下所示:

function PersonA() {
     return (
         <Info name="川川" age="一个靠前排的90后帅小伙"  />
     );
}
// 上面的return后面的等价于
function personA() {
    const props = { name: "川川", age:"一个靠前排的90后帅小伙"}
    return (
      <Info { ...props } />
    );
    
}

function Info(props){
    return (
        <div>{ props.name }--{ props.age }</div>
    );
}

const container = document.getElementById('root');

ReactDOM.render(<PersonA  />, container);

小tips:如何将一对象进行输出?

对于数组对象,可以通过map方法进行输出,然而假如是对象的话,却是没有这个方法的

具体使用的是Object.keys(对象)这个方法,它会返回一个数组,并且将对象的属性名保存在一个数组中,如果是要获取对象的属性值,则可以先转数组,然后在使用数组的一些方法:例如map方法进行处理一下

var obj = {
name: "川川",
age: "你猜,小鲜肉一枚"
}
var getAttr = Object.keys(obj);
var getValue = Object.keys(obj).map((item) => obj[item]);
console.log(getAttr); // ["name", "age"]
console.log(getValue);// ["川川", "你猜,小鲜肉一枚"]

如下真实例子如下所示

import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';


class List extends Component {
    constructor(props) {
    super(props);
    // 下面是为简化代码,绑定this 
    this.content = this.props.content;
    this.value = this.props.value;
}

render() {
return (
   <Fragment>
     <ul>
       {
         <li>{ this.content }-- { this.value }</li>
       }
     </ul>
   </Fragment>
);
}
}

class Person extends Component {
    constructor(props) {
    super(props);

    this.person = {
       name: "川川",
       age: "一个靠前排的90后帅小伙",
       desc: "欢迎关注微信itclanCoder公众号"
    }
}

render() {
   let getPerson = Object.keys(this.person);
   return (
     <Fragment>
     {
       getPerson.map((item) => <List key = { item }
                           content = { item }
                           value = { this.person[item]} />
                )
     }
     </Fragment>
);
}
}

const container = document.getElementById('root');

ReactDOM.render(<Person />, container);

最终的效果如下所示:


Object.keys().png

JSX中的props

自定义组件定义的属性称为prop,而属性值称为prop值,由于组件可以定义多个属性,所以可以由多种方式在JSX中指定props

由于JSX会被转换为React.createElement(组件元素, 属性对象, 子元素),例如:如下JSX

const info = {
      title:"我是一个组件",
      number: 20
}
// 将info对象存储到infoMessage变量属性中,并传给MyComponent组件
<MyComponent infoMessage = { info }>my component</MyComponent>
// 最终会被转化为
React.createElement(MyComponent, { infoMessage: info}, 'my component')

调用组件处,被称为父组件,而定义组件处,被称为子组件,对应的子组件想要接收父组件的值,用props去接收

label中的htmlFor

在原生html标签中label与input的结合使用,增大鼠标的触控范围,起到增强用户体验的作用

for在JSX中应该被写作htmlFor

<label htmlFor="firstname">First name:</label>
<input type="text" name="firstname" id="firstname">

结果如下所示


焦点htmlFor.gif

总结

本文主要讲述在JSX中添加属性的命名方式应是camelCase驼峰式命名来定义属性的名称,JSX中的子元素可以是字符串,可以嵌套,以及js表达式,函数都可以作为子元素

并且在React中组件的定义以及调用处,组件名称首字母必须要大写,当导出多个React组件时,使用点语法来引用一个React组件

使用展开运算符 ...在JSX中传递整个props对象

某些时候,是一个非常有用的语法,另外,当遍历要渲染的是一对象时,对象并没有数组的一些方法,通过Object.keys()进行转换,然后在使用.能够得到对象的属性以及属性值

也知道JSX中的何为prop,以及怎么去接收props值

对于label与input使用时,要注意的一些地方.

当然对于JSX的相关知识学习暂且就这么多了,仍然还有很多东西要学习的,编程是一门不断探索的艺术,希望分享的这些的这些对你有些用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350