Skip to main content

React 基础

React Native 的基础是React, 是在 web 端非常流行的开源 UI 框架。要想掌握 React Native,先了解 React 框架本身是非常有帮助的。本文旨在为初学者介绍一些 react 的入门知识。

本文主要会探讨以下几个 React 的核心概念:

  • components 组件
  • JSX
  • props 属性
  • state 状态

如果你想更深一步学习,我们建议你阅读React 的官方文档,它也提供有中文版。

尝试编写一个组件#

本文档会用“Cat”这种有个名字和咖啡馆就能开始工作的人畜无害的生物来作为例子。下面是我们的第一个 Cat 组件:

要定义一个Cat组件,第一步要使用import语句来引入React以及React NativeText组件:

import React from 'react';import { Text } from 'react-native';

然后一个简单的函数就可以作为一个组件:

const Cat = () => {};

这个函数的返回值就会被渲染为一个 React 元素。这里Cat会渲染一个<Text>元素:

const Cat = () => {  return <Text>Hello, I am your cat!</Text>;};

这里我们还使用了export default语句来导出这个组件,以使其可以在其他地方引入使用:

const Cat = () => {  return <Text>Hello, I am your cat!</Text>;};
export default Cat;

上面只是导出组件的写法之一。你还可以看看这篇博客整理handy cheatsheet on JavaScript imports and exports整理的各种不同的写法。

下面我们来看看这个return 语句。<Text>Hello, I am your cat!</Text>是一种简化 React 元素的写法,这种语法名字叫做 JSX。

JSX#

React 和 React Native 都使用JSX 语法,这种语法使得你可以在 JavaScript 中直接输出元素:<Text>Hello, I am your cat!</Text>。React 的文档有一份完整的JSX 指南可供你参考。因为 JSX 本质上也就是 JavaScript,所以你可以在其中直接使用变量。这里我们为猫猫的名字声明了一个变量name,并且用括号把它放在了<Text>之中。

``

括号中可以使用任意 JavaScript 表达式,包括调用函数,例如{getFullName("Rum", Tum", "Tugger")}

你可以把括号{}想象成在 JSX 中打开了一个可以调用 JS 功能的传送门!

因为 JSX 语法糖的实质是调用React.createElement方法,所以你必须在文件头部引用import React from 'react'

自定义组件#

你应该已经了解React Native 的核心组件了。 React 使得你可以通过嵌套这些组件来创造新组件。这些可嵌套可复用的组件正是 React 理念的精髓。

例如你可以把TextTextInput嵌入到View 中,React Native 会把它们一起渲染出来:

对开发者的提示#

如果你熟悉 web 开发,<View><Text>应该能让你想起 HTML。你可以把它们看作是应用开发中的<div><p>标签。

这样你就可以在别处通过<Cat>来任意引用这个组件了:

我们把包含着其他组件的组件称为父组件或父容器。这里Cafe是一个父组件,而每个Cat则是子组件

你的咖啡店里,想养多少只猫都行!注意每只<Cat>渲染的都是不同的元素——你可以使用不同的 props 属性来定制它们。

Props 属性#

Props 是“properties”(属性)的简写。Props 使得我们可以定制组件。比如可以给每只<Cat>一个不同的name

React Native 的绝大多数核心组件都提供了可定制的 props。例如,在使用Image组件时,你可以给它传递一个source属性,用来指定它显示的内容:

Image很多不同的 propsstyle也是其中之一,它接受对象形式的样式和布局键值对。

请留意我们在指定style属性的宽高时所用到的双层括号{{ }}。在 JSX 中,引用 JS 值时需要使用{}括起来。在你需要传递非字符串值(比如数组或者数字)的时候会经常用到这种写法:<Cat food={["fish", "kibble"]} /> age={2}。然而我们在 JS 中定义一个对象时,本来需要用括号括起来:{width: 200, height: 200}。因此要在 JSX 中传递一个 JS 对象值的时候,就必须用到两层括号:{{width: 200, height: 200}}

使用核心组件Text, Image以及View搭配 props 已经可以做不少东西了!但是如果想要做一些用户交互,那我们还需要用到状态(state)。

State 状态#

如果把 props 理解为定制组件渲染的参数, 那么state就像是组件的私人数据记录。状态用于记录那些随时间或者用户交互而变化的数据。状态使组件拥有了记忆!

按惯例来说,props 用来配置组件的第一次渲染(初始状态)。state 则用来记录组件中任意可能随时间变化的数据。下面示例的情景发生在一个猫咪咖啡馆中,两只猫咪正嗷嗷待哺。它们的饥饿程度会随着时间变化(相对地,它们的名字就不会变化),因此会记录在状态中。示例中还有一个喂食按钮,一键干饭,扫除饥饿状态!

你可以使用React 的useState Hook来为组件添加状态。Hook (钩子)是一种特殊的函数,可以让你“钩住”一些 React 的特性。例如useState可以在函数组件中添加一个“状态钩子”,在函数组件重新渲染执行的时候能够保持住之前的状态。要了解更多,可以阅读React 中有关 Hook 的文档

首先要从 react 中引入useState

import React, { useState } from 'react';

然后可以通过在函数内调用useState来为组件声明状态。在本示例中 useState 创建了一个 isHungry 状态变量:

const Cat = (props) => {  const [isHungry, setIsHungry] = useState(true);  // ...};

你可以使用useState来记录各种类型的数据: strings, numbers, Booleans, arrays, objects。例如你可以这样来记录猫咪被爱抚的次数:const [timesPetted, setTimesPetted] = useState(0)useState实质上做了两件事情:

  • 创建一个“状态变量”,并赋予一个初始值。上面例子中的状态变量是isHungry,初始值为true
  • 同时创建一个函数用于设置此状态变量的值——setIsHungry

取什么名字并不重要。但脑海中应该形成这样一种模式:[<取值>, <设值>] = useState(<初始值>).

下面我们添加一个按钮Button组件,并给它一个onPress的 prop:

<Button  onPress={() => {    setIsHungry(false);  }}  //../>

现在当用户点击按钮时,onPress函数会被触发,从而调用setIsHungry(false)。此时状态变量isHungry就被设为了false。当isHungry为 false 的时候,Buttondisabled属性就变成了true ,其title也相应变化:

<Button  //..  disabled={!isHungry}  title={isHungry ? 'Pour me some milk, please!' : 'Thank you!'}/>

你可能注意到虽然isHungry使用了常量关键字const,但它看起来还是可以修改!简单来说,当你调用setIsHungry这样的设置状态的函数时,其所在的组件会重新渲染。此处这一整个Cat函数都会从头重新执行一遍。重新执行的时候,useState会返回给我们新设置的值。

最后再把猫咪放进Cafe组件:

const Cafe = () => {  return (    <>      <Cat name="Munkustrap" />      <Cat name="Spot" />    </>  );};

注意到上面的<></>了吗? 这一对 JSX 标签称为Fragments(片段)。由于 JSX 的语法要求根元素必须为单个元素,如果我们需要在根节点处并列多个元素,在此前不得不额外套一个没有实际用处的View。但有了 Fragment 后就不需要引入额外的容器视图了。


现在你应该已经差不多了解 React 和 React Native 的核心组件与思想了。下面可以试着深入学习一些核心组件的用法,比如如何处理文本输入<TextInput>