【React Native】样式、网络请求和Loading

发布于:2025-07-13 ⋅ 阅读:(24) ⋅ 点赞:(0)

样式

React Native里写样式,必须使用StyleSheet.create来创建。必须要改成驼峰法来书写。

React Native里的排版布局,默认是使用flex的。也就说页面中的元素,默认就自带flex属性了,不需要自己额外添加display: 'flex'

Web不同的是,React Native里,flexDirection,默认是column,而不是row。这样子,页面上的元素,默认会从上向下排列。除此外,还有些其他属性的默认值不同,但用法都是和CSS一样的。

fontSize,后面的值,没有单位。在React Native里,这种值,是与设备像素密度无关的逻辑像素点,千万不要加上px

样式可以写成行内样式,也可以写成对象的形式,还可以同时使用:

<Text style={[styles.title, { fontSize: 50, width: 200 }]}>
  欢迎!
</Text>
  • 优先规则,并不是行内样式优先。而是后面的,会把前面的覆盖。

简单的一个demo,点击按钮count+1:

import { Button, StyleSheet, Text, View } from 'react-native';
import { useState } from 'react';

export default function App() {
  const [count, setCount] = useState(0);

  return (
    <View style={styles.container}>
      <Text>{count}</Text>
      <Button title="Click me" onPress={() => setCount(count + 1)} />
    </View>
  );
}

网络请求

一定要确保手机和电脑在同一局域网内,也就是说连的是同一台路由器。

React Native里读取接口,不需要额外安装任何依赖包,它里面自带Fetch API

/**
 * 获取搜索接口课程数据
 * @returns {Promise<void>}
 */
const fetchData = async () => {
  const res = await fetch('http://localhost:3000/search');
  const { data } = await res.json();
  setCourses(data.courses);
};
  • 获取到的数据是JSON格式的,这里要用.json()来解析一下。

使用Android模拟器,必须改为局域网 IP地址,用localhost无法读取接口。关于局域网 IP地址的获取方法,请查看获取 IP 地址命令

使用 React Native 调试工具, 继续在终端里,按m键,App上会弹出菜单,使用Open JS Debugger,就会打开调试工具。直接在终端里按j键,也可以打开调试工具

如果调试工具里,没有显示正确的数据。可能是调试工具,连接到之前运行的 App 上去了。可以在模拟器里或者真机里,将运行的 App 退出,然后按 i、a 或者扫码重新运行。

这里有个需要注意的问题,如果用手机真机来预览,在扫码后,点击按钮,会发现没有任何反应。

这是因为代码里写的接口地址是localhost,这是本机的意思,而手机上哪里有接口呢?所以根本请求不到。

咱们的接口是运行在电脑上的,解决方法就是要将请求地址,改成电脑的局域网 IP地址。

macOSWindows查看IP的命令不同。

  • macOS:
ifconfig | grep "inet " | grep -v 127.0.0.1
  • Windows:
ipconfig | findstr "IPv4"

我这里查出来有两个IP地址。这是因为电脑既插了网线,也连了Wi-Fi。它们两个都是正确的局域网 IP地址,任选其一就行。前面的http和后面的3000端口是不能丢的,只改localhost这里。

在这里插入图片描述

  • Windows电脑有可能还是访问失败,如果碰到这种情况了,关闭Windows系统设置里的防火墙。然后用手机浏览器直接访问:http://你的局域网IP地址:3000,确认接口是有响应的。
  • 切换网络,重启电脑,都可能会导致局域网 IP变更。这时候需重新获取IP地址,重新配置。

搜索功能 - 传参:

import { Button, StyleSheet, Text, TextInput, View } from "react-native";
import { useEffect, useState } from "react";

export default function App() {
  const [courses, setCourses] = useState([]);
  const [keyword, setKeyword] = useState("");

  /**
   * 获取搜索接口课程数据
   * @returns { Promise<void> }
   */
  const fetchData = async () => {
    const res = await fetch(`http://192.168.xx.xx:3000/search?q=${keyword}`);
    const { data } = await res.json();
    setCourses(data.courses);
    console.log("获取到的数据是:", data.courses);
  };

  useEffect(() => {
    fetchData();
  }, [keyword]);

  return (
    <View style={styles.container}>
      <Text>请输入关键字</Text>
      <TextInput
        style={styles.input}
        placeholder="请输入关键字"
        value={keyword}
        onChangeText={setKeyword}
        defaultValue={keyword}
      />
      {courses.map((course) => (
        <Text key={course.id}>{course.name}</Text>
      ))}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  input: {
    height: 40,
    width: 300,
    margin: 12,
    padding: 10,
    borderWidth: 1,
    borderColor: "#ccc",
    borderRadius: 5,
  },
});

Loading

在这里插入图片描述

import { useEffect, useState } from "react";
import { StyleSheet, Text, TextInput, View } from "react-native";
import Loading from "./components/shared/Loading";

export default function App() {
  const [courses, setCourses] = useState([]);
  const [keyword, setKeyword] = useState("");
  const [loading, setLoading] = useState(true);

  /**
   * 获取搜索接口课程数据
   * @returns { Promise<void> }
   */
  const fetchData = async () => {
    try {
      setLoading(true);
      await new Promise((resolve) => setTimeout(resolve, 2000));
      const res = await fetch(`http://192.168.xx.xx:3000/search?q=${keyword}`);
      const { data } = await res.json();
      setCourses(data.courses);
      console.log("获取到的数据是:", data.courses);
    } catch (error) {
      console.log("获取数据失败:", error);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchData();
  }, [keyword]);

  return (
    <View style={styles.container}>
      <Text>请输入关键字</Text>
      <TextInput
        style={styles.input}
        placeholder="请输入关键字"
        value={keyword}
        onChangeText={setKeyword}
        defaultValue={keyword}
      />
      {loading ? (
        <Loading />
      ) : (
        courses.map((course) => <Text key={course.id}>{course.name}</Text>)
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  input: {
    height: 40,
    width: 300,
    margin: 12,
    padding: 10,
    borderWidth: 1,
    borderColor: "#ccc",
    borderRadius: 5,
  },
});
import { ActivityIndicator, StyleSheet } from "react-native";

export default function Loading() {
  return (
    <ActivityIndicator size="small" color="#1f99b0" style={styles.loading} />
  );
}

const styles = StyleSheet.create({
  loading: {
    backgroundColor: "#fff",
    position: "absolute",
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    zIndex: 1,
  },
});

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到