react实战项目开发(2) react几个重要概念以及JSX语法

前言

前面我们已经学习了利用官方脚手架搭建一套可以应用在生产环境下的React开发环境。那么今天这篇文章主要先了解几个react重要的概念,以及讲解本文的重要知识JSX语法

React重要概念

【思想】
React 的核心思想是:封装组件,各个组件维护自己的状态和 UI,当状态变更,自动重新渲染整个组件。

如果我们使用react编写的话,会把他拆分成一个一个的小组件进行编写方便管理复用性高,例如我们把登录拆分成一个组件编写,如果以后公司其它地方需要用到,那么就可以直接使用。

看一段代码感受下:

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

class HelloMessage extends Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

// 加载组件到 DOM 元素 mountNode
render(<HelloMessage name="John" />, mountNode);

【组件】
React 应用都是构建在组件之上。

上面的 HelloMessage 就是一个 React 构建的组件,最后一句 render 会把这个组件显示到页面上的某个元素 mountNode 里面,显示的内容就是 <div>Hello John</div>。

props 是组件包含的两个核心概念之一,另一个是 state(这个组件没用到)。可以把 props 看作是组件的配置属性,在组件内部是不变的,只是在调用这个组件的时候传入不同的属性(比如这里的 name)来定制显示这个组件。

【JSX】
从上面的代码可以看到将 HTML 直接嵌入了 JS 代码里面,这个就是 React 提出的一种叫 JSX 的语法,这应该是最开始接触 React 最不能接受的设定之一,因为前端被“表现和逻辑层分离”这种思想“洗脑”太久了。但实际上组件的 HTML 是组成一个组件不可分割的一部分,能够将 HTML 封装起来才是组件的完全体,React 发明了 JSX 让 JS 支持嵌入 HTML 不得不说是一种非常聪明的做法,让前端实现真正意义上的组件化成为了可能。

好消息是你可以不一定使用这种语法,后面会进一步介绍 JSX,到时候你可能就会喜欢上了。现在要知道的是,要使用包含 JSX 的组件,是需要“编译”输出 JS 代码才能使用的。

【Virtual DOM】
当组件状态 state 有更改的时候,React 会自动调用组件的 render 方法重新渲染整个组件的 UI。

当然如果真的这样大面积的操作 DOM,性能会是一个很大的问题,所以 React 实现了一个Virtual DOM,组件 DOM 结构就是映射到这个 Virtual DOM 上,React 在这个 Virtual DOM 上实现了一个 diff 算法,当要重新渲染组件的时候,会通过 diff 寻找到要变更的 DOM 节点,再把这个修改更新到浏览器实际的 DOM 节点上,所以实际上不是真的渲染整个 DOM 树。这个 Virtual DOM 是一个纯粹的 JS 数据结构,所以性能会比原生 DOM 快很多。

【Data Flow】
“单向数据绑定”是 React 推崇的一种应用架构的方式。当应用足够复杂时才能体会到它的好处,虽然在一般应用场景下你可能不会意识到它的存在,也不会影响你开始使用 React,你只要先知道有这么个概念。

JSX语法

看如下变量的定义:如果是字符串应该添加引号,但是却直接把DOM结构赋值给一个变量?什么操作?这就是JSX

const element = <h1>Hello, world!</h1>;

它被称为 JSX, 一种 JavaScript 的语法扩展。 我们推荐在 React 中使用 JSX 来描述用户界面。JSX 看起来可能比较像是模版语言,但事实上它完全是在 JavaScript 内部实现的。

【语法糖】
本质上讲JSX只是为React.createElement(component, props, ...children) 方法提供的语法糖

<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>

等同于下面
React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)

使用上篇文章搭建好的项目,并进行瘦身,然后新建一个组件JsxCom.js 并且引入到App.js中,代码如下:

App.js

import React, { Component } from 'react';
import JsxCom from './JsxCom';

class App extends Component {
  render() {
    return (
      <div className="App">
        <JsxCom />
      </div>
    );
  }
}
export default App;

JsxCom.js

import React, { Component } from 'react';

class JsxCom extends Component {
  render() {
    return (
      <div className="JsxCom">
      </div>
    );
  }
}

export default JsxCom;

JSX 规则

以下几点是刚开始写React时比较容易忽视的规则

【制定React元素】
<JsxCom /> 首字母大写的类型表示 JSX 标签引用到一个 React 组件。这些标签将会被编译为直接引用同名变量,所以如果你使用了 <JsxCom /> JSX 表达式,则 JsxCom 必须在作用域中。

【React 必须在作用域中】
由于 JSX 编译成React.createElement方法的调用,所以在你的 JSX 代码中,React库必须也始终在作用域中。也就是最上面必须引入React

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

【在运行时选择类型】

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  // 错误!JSX 标签名不能为一个表达式。
  return <components[props.storyType] story={props.story} />;
}

如下方式才是正确的:
function Story(props) {
  // 正确!JSX 标签名可以为大写开头的变量。
  const SpecificStory = components[props.storyType];
  return <SpecificStory story={props.story} />;
}

JSX 语法

【JSX的属性(Props)表达式】
你可以传递JavaScript 表达式作为一个属性,再用大括号{}括起来。例如,在这个 JSX 中:

<JsxCom foo={1+2+3}>

【在 JSX 中使用表达式】

直接看代码

class JsxCom extends Component {
    user = {
        firstName: 'Harper',
        lastName: 'Perez'
    };

    formatName(user) {
        return user.firstName + ' ' + user.lastName;
    }

    render() {
      return (
        <div className="JsxCom">
          <h1>
            Hello, {this.formatName(this.user)}!
          </h1>
        </div>
      );
    }
}

分析:定义了一个字面量对象user,定义了一个函数formatName,输出一个字符串。最后我们在render函数中{this.formatName(this.user)} 使用该函数

【JSX中if语句和for语句的应用】

if 语句和 for 循环在 JavaScript 中不是表达式,因此它们不能直接在 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>;
}

【字符串常亮】

<MyComponent message="hello world" />

<MyComponent message={'hello world'} />

【JSX 属性】

// 使用引号来定义以字符串为值的属性
const element = <div tabIndex="0" className="hello"></div>;

// 使用表达式
const element = <img src={user.avatarUrl} />;

因为 JSX 的特性更接近 JavaScript 而不是 HTML , 所以 React DOM 使用 camelCase 小驼峰命名 来定义属性的名称,而不是使用 HTML 的属性名称。

例如,class 变成了 className,而 tabindex 则对应着 tabIndex。

【属性默认为“True”】
如果你没有给属性传值,它默认为 true。

<MyTextBox autocomplete />
等价于
<MyTextBox autocomplete={true} />

【展开属性】
如果你已经有了个 props 对象,并且想在 JSX 中传递它,你可以使用 ... 作为“展开(spread)”操作符来传递整个属性对象。下面两个组件是等效的:

function App1() {
  return <Greeting firstName="Ben" lastName="Hector" />;
}

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

【JSX中的子代】
在既包含开始标签又包含结束标签的 JSX 表达式中,这两个标签之间的内容被传递为专门的属性:props.children。

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

<MyComponent>Hello world!</MyComponent>

这是有效的 JSX,并且 MyComponent 的 props.children 值将会直接是 "hello world!"

[2]嵌套React组件

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

[3]JavaScript 表达式作为子代
你可以将任何 {} 包裹的 JavaScript 表达式作为子代传递。例如,下面这些表达式是等价的:

<MyComponent>foo</MyComponent>

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

[4]函数作为子代
通常情况下,插入 JSX 中的 JavaScript 表达式将被认作字符串、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 都是有效的子代,只是它们不会被渲染。下面的JSX表达式将渲染为相同的东西:

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

相反,如果你想让类似 false、true、null 或 undefined 出现在输出中,你必须先把它转换成字符串 :

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

【JSX 防注入攻击】

const title = response.potentiallyMaliciousInput;
// 直接使用是安全的:
const element = <h1>{title}</h1>;

React DOM 在渲染之前默认会 过滤 所有传入的值。它可以确保你的应用不会被注入攻击。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(跨站脚本) 攻击。

原文地址:https://www.cnblogs.com/shiyou00/p/10721279.html

时间: 2024-09-30 01:36:39

react实战项目开发(2) react几个重要概念以及JSX语法的相关文章

Expo大作战--针对已经开发过react native项目开发人员有针对性的介绍了expo,expo的局限性,开发时项目选型注意点等

简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo依赖,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人修改补充+demo测试的形式,对expo进行一次大补血!欢迎加入expo兴趣学习交流群:597732981 [之前我写过一些列关于expo和rn入门配置的东i西,大家可以点击这里查看:从零学习rn开发] 相关文章: Expo大作战--什么是expo,如何安装expo clinet和xde,xde如何

01. SpringCloud实战项目-五分钟搞懂分布式基础概念

SpringCloud实战项目全套学习教程连载中 PassJava 学习教程 简介 PassJava-Learning项目是PassJava(佳必过)项目的学习教程.对架构.业务.技术要点进行讲解. PassJava 是一款Java面试刷题的开源系统,可以用零碎时间利用小程序查看常见面试题,夯实Java基础. PassJava 项目可以教会你如何搭建SpringBoot项目,Spring Cloud项目 采用流行的技术,如 SpringBoot.MyBatis.Redis. MySql. Mon

Android快乐贪吃蛇游戏实战项目开发教程-01项目概述

一.项目简介贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏.我已经将做好的案例上传到了应用宝,大家可以下载下来把玩一下.为了和其它的贪吃蛇区别开来,我取名叫“快乐贪吃蛇”.应用宝链接:http://sj.qq.com/myapp/detail.htm?apkName=net.chengyujia.happysnake这里上两张截图先睹为快,哈哈.怎么玩大家应该都知道,不过我还是要多提一下.通过屏幕上的方向键控制蛇的前进方向.蛇每吃到一个食物身体会

vue php实战项目开发(一)

说在前面 项目开发过程中一直在学习,所以记录的过程可能比较乱,打算前台使用vue,后台使用php开发手机端的项目,这里记录遇到的问题和学习的过程 phpstudy环境下搭建虚拟域名,并开启URL重写 打开appache这里注意是E:phpStudyApacheconf文件夹下的vhosts.conf里配置我从网上查的是要配置E:phpStudyApacheconfextra的httpd-vhosts.confE:phpStudyApacheconfvhosts.conf <VirtualHost

【轻松一刻】实战项目开发(三) 分享文本内容至微信

首先需要在微信开放平台创建应用 并等待审核通过. 需要注意包名,签名不要写错了.创建的应用可以是暂时没有上线了, 应用名称中不能含有微信二字,否则会被驳回,一般一至两天就能通过. 注意 严格按照 开发指南或者参考SDK Sample Demo步骤来,不能少. 使用android tools 导出带签名的apk,不要使用run as. 如果配置信息中打开了代码混淆,为了保证sdk的正常使用, 需要在proguard.cfg加上下面两行配置: -keep class com.tencent.mm.s

【轻松一刻】实战项目开发(零)

新建项目 使用Fragment实现tab页面的效果 自定义对话框控件 IOSAlertDialog 使用聚合数据sdk 请求数据. 获得返回的json字符串. 使用Gson解析Json数据 得到list<Data>数据,设置adapter数据集 引入下拉刷新控件. 自定义listview中item的布局 解决list列表中数据重复的问题 申请微信分享权限 添加分享文本 没有网络时 给与提示 离线状态下加载本地缓存数据

Android快乐贪吃蛇游戏实战项目开发教程-06虚拟方向键(五)绘制方向键箭头

本系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html本系列教程项目源码GitHub地址:https://github.com/jackchengyujia/HappySnake 一.本文概述 在上篇教程中,我们画了4个背景三角形,并且实现了点击变色的按钮效果.在本篇教程中,我们将在这4个三角形上分别绘制表示方向的箭头,并且让箭头也有点击变色的效果.我们先看一下运行效果,有一个直观的了解,然后再从代码的角度分析和讲解. 二.运行效果

Android快乐贪吃蛇游戏实战项目开发教程-03虚拟方向键(二)绘制一个三角形

该系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html 一.绘制三角形 在上一篇文章中,我们已经新建了虚拟方向键的自定义控件DirectionKeys类,下面我们继续. 本项目中的虚拟方向键的背景是4个三角形组成的矩形,其实是4个三角形的按钮. 系统自带的按钮是矩形的,怎么做一个三角形按钮呢? 首先我需要了解,所有控件的外观都是画出来的,当然不是我们手工去画而是用程序去画. 用程序怎么画呢? 很多技术平台上都有绘图功能,用起来也很相

【轻松一刻】实战项目开发(二) list数据去重 数据追加与缓存

引入开源控件 PullToRefresh 下拉刷新列表 每次下拉刷新都会发送请求,从接口返回json信息. 如果前后两次请求返回的数据中有重复的数据 该怎么给list去重 在上一篇中我们重写了实体Data的hashcode和equals方法 /** * 因为更新时间和unixtime都不是唯一的 * 这里使用唯一标识hashId来得到哈希码 */ @Override public int hashCode() { final int prime = 31; int result = 1; res