一、理解JSX

1、JSX是JavaScript XML,是一种语法,由Meta公司发布,浏览器是不支持这种语法的

2、在编写React组件视图结构时,JSX是可选的
JSX语法:

function B(props) {
    return (
        <div>
            <h1>你好</h1>
        </div>
    )
}

不用JSX语法,用React官方API:

function B() {
    return React.createElement('div', {}, React.createElement('h1', {}, '你好'))
}

可以使用React.createElement('tag', {}, [])编写视图结构,组件是一定要有视图结构的

3、JSX语法最终会被@babel/preset-react进行编译,编译的结果就是React.createElement()这种语法

4、要随时有能力把JSX语法转换成React.createElement()语法,反之亦然

5、什么是JSX元素:React.createElement()的结果,是变量,也是对象,并且是不可变对象
例子:React.createElement('div', {}, '你好') 等价于 <div>你好</div>

const element1 = <div>你好</div>
console.log('---element1', element1)
const element2 = React.createElement('div', {}, '你好')
console.log('---element2', element2)

控制台打印:

可以看到element1和element2都是react.transitional.element类型

6、为什么JSX元素要设计成不可变对象
因为JSX元组最终会被渲染成真实DOM,所以不能直接操作“原材料”。要改变只能采用声明式操作

7、元素和组件的区别
组件是由class或function定义的东西,叫组件
元素是由JSX语法或React.createElement()返回的结果叫做元素
组件实例化了就是元素

二、JSX语法细节

1、在JSX中可以嵌套表达式,使用{}来嵌套
在JSX视图中,凡是动态的变量(表达式)都使用{}包起来

const hello = '你好'
const title = '标题'

function B() {
    return (
        <div title={ title }>
            <h1>{ hello }</h1>
        </div>
    )
}

2、当JSX定义视图比较复杂时,建议换行,像HTML那样对齐,换行后建议用()把JSX元素整体包裹起来

const ele = (
    <div>
        <h1>你好</h1>
    </div>
)

3、JSX写法是变量,也是表达式,所以JSX元素可以作为函数的入参,也可以作为函数的返回值,还可以用在if/for循环中

function handle (arg) {
    if (arg) {
        return <div>{arg}</div>
    } else {
        return <div>你好</div>
    }
}

调用:

handle('你好')
handle(100)
handle(<span>大家好</span>)

如果arg是个JSX,能不能在{}内对它做操作,<div>{arg + 1}</div>?
回答:不能,arg是JSX不要做操作,直接渲染就行了

4、JSX语法有三个HTML属性发生了变化:
(1)className代替class,因为JSX中class是关键字
(2)tabIndex代替tabindex,因为JSX使用小驼峰命名法
(3)htmlFor代替for,因为和for循环的for重复

5、JSX语法中有三个新增的属性
(1)key,用于列表渲染
(2)ref,快捷的DOM访问方式
(3)dangerouslySetInnerHTML,用于渲染一段HTML片段
举例:
我们写了一个变量content,React默认是字符串,不会解析标签,就按照字符串显示

const hello = '你好'
const title = '标题'

function B() {
    return (
        <div title={ title }>
            <h1>{ hello }</h1>
            <div>{ content }</div>
        </div>
    )
}

const content = '<div><a href="https://www.baidu.com">跳转</a></div>'

export default B

使用dangerouslySetInnerHTML属性:


const hello = '你好'
const title = '标题'

function B() {
    return (
        <div title={ title }>
            <h1>{ hello }</h1>
            <div dangerouslySetInnerHTML={{ __html: content }}></div>
        </div>
    )
}

const content = '<div><a href="https://www.baidu.com">跳转</a></div>'

export default B


React写进{}内的东西,不允许被当作代码块解析,是为了防止xss攻击和代码注入

6、JSX中,不仅自定义组件可以使用单闭合,任何html标签都可以用单闭合

7、JSX中,内联style的语法,<div style={{cssKey1:'cssValue1', cssKey2:'cssValue2'}} />

8、className语法:<div className='box' className={cc}></div>
box是字符串,cc是变量或表达式

9、在JSX中,使用{}渲染后端接口数据,默认支持防注入攻击(XSS)

10、JSX是对象,因为Babel将JSX编译成React.createElement()调用的返回值,这个返回值是对象结构,所以jSX是对象。这种JSX对象就是“Fiber单元”,Fiber树就是由这些单元串联起来的,是一个双向链表结构

三、深入JSX

1、从本质上讲,JSX只是React.createElement()函数提供的语法糖

2、如果节点不存在子节点,可以使用自闭合格式的标签

3、如果你希望测试某些特别的JSX是如何被转换成JavaScript的,可以尝试使用在线Babel编译器

4、一个JSX标签的开始部分决定了React元素的类型
所有的React组件(由class或function定义)的组件名称,都必须以大写字母开头。比如<A />、<MyButton />

// 这是普通的函数声明,不是JSX语法支持的组件,用法:b()
function b () {
    return (
        <div>你好</div>
    )
}

// 这才是真正的React组件,支持JSX语法,用法:<B />
function B () {
    return (
        <div>你好</div>
    )
}

5、因为JSX被编译为React.createElement的调用,所以React库必须在你JSX代码的作用域中

6、JSX支持“点语法”调用组件,比如React.Component、<B.Button />

const QQ = {
    Button () {
        return (<button>点击</button>)
    },
    Model: function () {
        return (<div>弹框</div>)
    }
}

使用:

<QQ.Button />
<QQ.Model />

7、不能使用一个普通表达式作为React元素类型,表达式要赋值给一个以大写字母开头的变量
例如:App是父组件,B是子组件

import PropTypes from 'prop-types';

function PhotoList (props) {
    return <h1>照片列表 { props.num } 条</h1>;
}

function VideoList (props) {
    return <h1>视频列表 { props.num } 条</h1>;
}

const pv = {
    photo: PhotoList,
    video: VideoList
};

function B(props) {

    const MediaList = pv[props.type||'photo'];

    return (
        <div>
            <MediaList num = {5} />
        </div>
    );
}

// 添加 PropTypes 验证
B.propTypes = {
    type: PropTypes.string
};

PhotoList.propTypes = {
    num: PropTypes.number
};

VideoList.propTypes = {
    num: PropTypes.number
};

export default B;

在return里不能直接用pv变量,要把pv变量赋值给一个以大写字母开头的变量

效果:

8、props属性
(1)对自定组件来讲,props是自定义属性
(2)用{}包裹的JavaScript表达式可以作为props属性
例子:<MediaList num = {1 + 2 + 2} />
(3)props里不能写if语句、for循环、switch语句
(4)可以接收函数调用的返回值
例子:<MediaList num = Math.random() />
(5)可以传入一个字符串字面量作为一个props属性
<MyComponent message="hello" />
等价于
<MyComponent message = {'hello'} />
(6)如果没有给props属性传值,那么它默认为true

9、属性展开语法
如果有个变量包含了props的内容,想传入整个对象,可以用扩展操作符...传入

function Child(props) {
    const { name, age, addr } = props;
    return (
        <div>{name} : {age} : {addr}</div>
    );
}

function B(props) {

    const childProps = {
        name: '张三',
        age: 18,
        addr: '北京'
    };

    return (
        <div>
            <Child {...childProps} />
        </div>
    );
}

效果:

10、什么是props.children,组件嵌套的内容
当我们在使用自定义组件时,那些被自定义组件所嵌套的内容,在子组件中使用props.children来接收

function Child(props) {
    const { name, age, addr, children } = props;
    // 处理children渲染问题
    let childrenResult = null;
    if (typeof children === 'function') {
        childrenResult = children();
    } else if (children) {
        childrenResult = children;
    }
    return (
        <div>
            <div>{name} : {age} : {addr}</div>
            <div>{childrenResult}</div>
        </div>
    );
}

function B(props) {

    const childProps = {
        name: '张三',
        age: 18,
        addr: '北京'
    };

    return (
        <div>
            <Child {...childProps} >
                { ()=>("子组件内容") }
            </Child>
        </div>
    );
}

效果:

11、props.children可以是任何类型的数据,比如基本数据类型、引用数据类型、也可以是函数、null、undefined

12、在JSX语法中,默认就支持对数组的直接渲染

<div>{ [ <div key={1} style={{color:'red'}}>数组内容</div>, true, null, 100, JSON.stringify({a:1,b:2}), [1,2,3] ] }</div>

效果:

13、在JSX中,使用{}渲染Boolean、null、undefined,都会被忽略,也就是说不生成文本节点

14、React组件也可以返回一个元素数组
在React中,封装组件时,无论是类组件render的返回值,还是函数式组件的返回值,还可以是数组

function MyList() {
    return [
        <>
        <div key={1}>数组内容1</div>
        <div key={2}>数组内容2</div>
        <div key={3}>数组内容3</div>
        </>
    ]
}

效果:

更多推荐