Home 读《Fullstack React Native》(二)
Post
Cancel
Preview Image

读《Fullstack React Native》(二)

七步法构建 RN 应用

这本书的第二章,用了一个新的示例应用:计时器,介绍了构建 RN 应用的七步法,分别是:

  1. 把应用分解为不同的组件。
  2. 开始构建一个静态的应用。
  3. 决定哪些数据需要使用 state 来保存状态。
  4. 决定这些 state 应该存在在哪个组件中。
  5. 先用 hardcode 的初始状态。
  6. 添加数据流动逻辑,包括向上的数据流动。
  7. 添加和服务器的通信。

这个计时器应用长这样子:

整章主要是采用该七步法,去实际的写代码来实现这个计时器,使我们能够真正理解这个方法,没有介绍新的关于 RN 的核心概念,这里我对自认为有用的两点做了笔记。

Class components vs Functional components

在上一章中,我们创建组件使用的都是 Class components, 本章介绍了另外一种方式 Functional components 。下面通过一个简单的例子对比一下:

1
2
3
4
5
6
7
8
9
10
class ClassComponent extends React.Component {
  render() {
    const { name } = this.props;
    return <Text>Hello, { name }</Text>;
 }
}

const FunctionalComponent = ({ name }) => {
 return <Text>Hello, {name}</Text>;
};

Functional components 可以被认为是只需要实现 render() 方法的组件,他们不管理 state ,也不需要关注 React 特殊的生命周期。props 被作为第一个参数传入并解构。

书中比较推荐的是 Functional components,有两个主要原因:

  1. 它能促使程序员在更少的地方管理 state,使程序更易懂。
  2. 它能使我们创建高可复用的组件,因为它所有的配置都需要从外面传进去。

需要使用 State 的判定标准

在第三步中,需要决定哪些数据需要使用 state,这里 Facebook 在 Thinking In React 这篇文章中,给了三个评判标准:

  1. 该数据是通过 props 从父组件中传入的吗?如果是,那它可能不是一个 state。
  2. 该数据会在后续被改变吗?如果不会,那它可能不是一个 state。
  3. 该数据可以根据组件中其他的 state 或者 props 计算得出吗?如果是,那它可能不是一个 state。

Core Components

View

View 在 RN 中是被广泛使用的,它通常在以下两种情况下使用:

  • 使用 View 来进行布局,对其中的子视图进行横向或纵向排列。
  • 使用 View 来添加样式,例如添加边框、背景色等等。

布局

Flex

RN 中的布局方式和前端类似,主要采用 flex 进行布局。在父视图上,有三个属性可供我们使用:

  • flexDirection
  • justifyContent
  • alignItems

flexDirection 控制子组件的主轴方向,可选的值如下:

justifyContent 控制子组件沿着主轴的排列方式,因此会受到主轴方向的影响,它可选的值如下:

alignItems 控制子组件沿着交叉轴的排列方式,因此也会受到主轴方向的影响,它可选择的值如下:

关于 flex 的使用,更详细的用法可以参考官方文档 Layout with Flexbox

Position

Position 这种布局方式是无视它的兄弟视图的,可能会使得视图重叠,它有两个值可以选择:

  • relative:在视图被布局好之后,对其进行位置的调整
  • absolute:完全无视其他布局对它的影响,只相对于父视图进行布局

比如如下的布局,会使得视图填充满父视图

1
2
3
4
5
6
7
const absoluteFillStyle = {
  position: 'absolute',
  top: 0,
  right: 0,
  bottom: 0,
  left: 0,
};

Box Model

RN 中对于间距的设置和 Web 中是一样的,都是用 Box Model, 一般通过设置 marginpadding 就能满足我们的需求。

当我们使用 widthheight 时,指的是 content 的宽高加上 padding 和 border,不包括 margin。

Text

Text 组件是有它的固有尺寸的,这和 iOS 开发中类似,渲染所需的文本所需要的宽高就是它默认的尺寸。

Text 是比较简单的,那些常见的属性它都有,比如 color fontFamily fontSize textAlign numberOfLines

TouchableOpacity

这个组件和 View 类似,不同的是它可以接受点击事件,并且会在按下和释放的时候附带有动画效果,可以修改 activeOpacity 来调整动画对透明度的改变量。

如果想要背景色改变的动画,可以使用 TouchableHighlight。这两个组件都只能有一个子组件,这是它们的一点限制。

Image

它可以通过 source 来渲染本地或者来自 URI 的图片。如果要设置图片的填充模式,可以使用 resizeMode

ActivityIndicator

它会渲染 iOS 和 Android 平台上默认的 Loading 动画。

FlatList

这是用来渲染长列表的组件,它接受一个 data 的数据列表还有每个列表元素组件的构建方法 renderItem。它每次只会渲染一屏的组件来提升性能。

TextInput

文本输入框,主要用到的属性有 valueonChangeTextonSubmitEditing

ScrollView

在渲染少量的需要滑动展示的视图时,可以使用 ScrollView,它不像 FlatList 那样每次只渲染一屏的组件,而是会将所有的组件全部渲染,所以只能用于少量数据的展示,否则会有性能问题。

用来展示模态视图的容器,用法如下,通过 visible 来控制其显示:

1
2
3
4
5
6
7
8
<Modal
  visible={showModal}
  animationType="slide"
  onRequestClose={this.closeCommentScreen}
>
  <Comments/>
</Modal>

Core APIs

除了内置的组件之外,还有一些功能需要调用 API 来实现,比如存储、获取网络状况等。我们可以遵循以下方法来调用 RN 的 API:

  1. 先根据需求确定我们需要调用哪个 API
  2. 确定调用的位置,例如在某个生命周期的方法或者工具类中
  3. 调用 API,要注意是异步还是同步
  4. 在组件的 state 中存储返回的结果
  5. 根据最新的 state 来重新渲染 UI

AsyncStorage

RN 提供了 AsyncStorage 来做少量的字符串存储,它通过键值对然后序列化成 Json 去存储,基础的 API 是:

1
2
AsyncStorage.getItem(key)
AsyncStorage.setItem(key, value)

如果要存储对象,需要先转成 Json 字符串,取出之后也需要解析成对象去使用。

1
2
JSON.stringify(object)
JSON.parse(jsonString)

StatusBar

RN 提供了两种方式来调整状态栏的 UI。

一种是通过组件。这个组件可以放在任意的组件树中:

1
2
3
4
5
6
7
const statusBar = (
  <StatusBar
    backgroundColor={backgroundColor}
    barStyle={isConnected ? 'dark-content' : 'light-content'}
    animated={false}
  />
);

第二种方法是调用 API:

1
StatusBar.setBarStyle(info === 'none' ? 'light-content' : 'dark-content');

NetInfo

这是用来获取网络状态的 API

下面这个 API 能够获取到当前的网络状态,返回的值可能为 wificellular 或者 none

1
const info = await NetInfo.getConnectionInfo();

同时也可以监听网络的变化

1
2
3
4
5
6
7
8
9
10
11
async componentWillMount() {
  this.subscription = NetInfo.addEventListener('connectionChange', this.handleChange);
}

componentWillUnmount() {
  this.subscription.remove();
}

handleChange = (info) => {
  this.setState({ info });
};

Alert

下面是 RN 中显示 Alert 的 API,会分别在 iOS 和 Android 上渲染 Alert 组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
handlePressMessage = () => {
  Alert.alert(
    'Delete message?',
    'Are you sure you want to permanently delete this message?',
    [
      {
        text: 'Cancel',
        style: 'cancel',
      },
      {
        text: 'Delete',
        style: 'destructive',
        onPress: () => {
          const { messages } = this.state;
          this.setState({
            messages: messages.filter(message => message.id !== id),
          });
        },
      },
    ],
  );
};

Geolocation

获取位置的 API:

1
2
3
navigator.geolocation.getCurrentPosition(position => {
  const { coords: { latitude, longitude } } = position;
});

Dimensions

获取设备屏幕的宽高可以使用这个 API,要注意获取到的值是当前的屏幕宽高,如果旋转屏幕之后需要重新调用获取。

1
2
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;

组件生命周期

参考

This post is licensed under CC BY 4.0 by the author.

读《Fullstack React Native》(一)

读《应对孩子的愤怒与攻击》

Comments powered by Disqus.