React基础3不可不知的JSX

4次阅读

共计 7490 个字符,预计需要花费 19 分钟才能阅读完成。

前言

  1. JSX 中添加属性有什么要注意的? 以及 JSX 中的子元素是怎么操作的?
  2. 组件的大小写问题, 使用拓展运算符, 以及怎么循坏遍历一个对象
  3. JSX 中的 prop 指的是什么? 以及表单的 labe 应该要注意什么?

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

JSX 添加特定属性

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

例如: 如下所示

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

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

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

至于更多插值表达式内容, 你可以看上一节 React 学习 (2)- 深入浅出 JSX
这里要提一下, 在属性中嵌入 javascript 表达式, 不要在双大括号外面加上引号, 例如, 下面的是错误的

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

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

注意

JSX 语法是更接近 Javascript 而不是 HTML,只是长得像而已,对于 Reat 中自定义组件的属性名称, 使用 camelCase 驼峰式命名来定义属性的名称, 例如: 定义 JSX 里的 class 属性 className, 而 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);

效果如下所示:

  • 函数作为子元素

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

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

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

效果如下所示:

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

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

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

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

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

使用大写字母开头命名自定义组件, 这是一种约定俗成的规定, 本质上它就是一构造函数, 是为了区别普通函数的, 模拟类的功能, 但 Es6 提供了类的语法, 以后更多的使用的还是 Es6 的 class

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

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

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

例如: 如下所示

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

// 以下是定义的函数组件, 首字母小写, 这个是不正确的
function myButton(props) {
return (
  <div>
   <button>{props.content}</button>
  </div>
)
}
function OutButton(){
  return (<myButton content="按钮" />);
}
const container = document.getElementById('root');
ReactDOM.render(<OutButton />, container);
// 正确的写法, 首字母大写, 驼峰式命名
function MyButton(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);

最终结果如下图所示:

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

拓展运算符, 属性展开

对于拓展运算符 (...), 是一个非常有用的语法, 如果你已经有了一个 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);

最终的效果如下所示:

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

对于怎么校验 JSX 转换为 React.createElement()可以去 babel 在线编译的官网校验的

打开如下网址即可

babeljs 转换

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

label 中的 htmlFor

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

for 在 JSX 中应该被写作 htmlFor

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

结果如下所示

结语

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

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

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

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

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

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

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

正文完
 0