• 作者:老汪软件技巧
  • 发表时间:2024-10-06 10:00
  • 浏览量:

环境搭建

首先,确保你的开发环境已经安装了 Node.js 和 npm。接下来,安装 Expo CLI:

npm install -g expo-cli

创建项目

使用 Expo CLI 创建一个新的 React Native 项目:

expo init MyAwesomeApp
cd MyAwesomeApp

选择一个模板(例如 blank)并初始化项目。接下来,启动开发服务器:

expo start

基本组件

我们从一个简单的首页开始,包含一个标题和一个按钮。

编辑 App.js

打开 App.js 文件,并替换默认内容:

// App.js
import React from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
const App = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welcome to My Awesome App!Text>
      <Button title="Click Me!" onPress={() => alert('Button clicked!')} />
    View>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
});
export default App;

状态管理

为了更好地管理状态,我们可以使用 React 的 useState 钩子。

添加计数器

在 App.js 中添加一个计数器:

// App.js
import React, { useState } from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
const App = () => {
  const [count, setCount] = useState(0);
  const increment = () => {
    setCount(count + 1);
  };
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welcome to My Awesome App!Text>
      <Text>Count: {count}Text>
      <Button title="Increment" onPress={increment} />
    View>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
});
export default App;

网络请求

接下来,我们添加一个功能来获取数据,并显示在界面上。

添加网络请求

在 App.js 中添加网络请求:

// App.js
import React, { useState, useEffect } from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
const App = () => {
  const [count, setCount] = useState(0);
  const [data, setData] = useState(null);
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then((response) => response.json())
      .then((json) => setData(json))
      .catch((error) => console.error(error));
  }, []);
  const increment = () => {
    setCount(count + 1);
  };
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welcome to My Awesome App!Text>
      <Text>Count: {count}Text>
      <Button title="Increment" onPress={increment} />
      {data && (
        <View style={styles.dataContainer}>
          <Text style={styles.label}>Title: {data.title}Text>
          <Text style={styles.label}>Completed: {data.completed ? 'Yes' : 'No'}Text>
        View>
      )}
    View>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  dataContainer: {
    marginTop: 20,
  },
  label: {
    fontSize: 18,
    marginVertical: 5,
  },
});
export default App;

样式与布局

为了使界面更加美观,我们可以使用 Flexbox 布局。

更新样式

在 App.js 中更新样式:

// App.js
import React, { useState, useEffect } from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
const App = () => {
  const [count, setCount] = useState(0);
  const [data, setData] = useState(null);
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then((response) => response.json())
      .then((json) => setData(json))
      .catch((error) => console.error(error));
  }, []);
  const increment = () => {
    setCount(count + 1);
  };
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welcome to My Awesome App!Text>
      <View style={styles.buttonContainer}>
        <Text style={styles.countText}>Count: {count}Text>
        <Button title="Increment" onPress={increment} />
      View>
      {data && (
        <View style={styles.dataContainer}>
          <Text style={styles.label}>Title: {data.title}Text>
          <Text style={styles.label}>Completed: {data.completed ? 'Yes' : 'No'}Text>
        View>
      )}
    View>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    paddingHorizontal: 20,
    paddingVertical: 40,
    alignItems: 'center',
    justifyContent: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  buttonContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    width: '100%',
    marginBottom: 20,
  },
  countText: {
    fontSize: 18,
    marginRight: 10,
  },
  dataContainer: {
    marginTop: 20,
  },
  label: {
    fontSize: 18,
    marginVertical: 5,
  },
});
export default App;

原型展示工具__原型快速开发工具

路由与导航

为了实现多页面应用,我们需要使用 React Navigation。

安装依赖

安装 React Navigation 和相关依赖:

expo install @react-navigation/native @react-navigation/stack

配置导航

在 App.js 中配置导航:

// App.js
import React from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
const HomeScreen = ({ navigation }) => {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welcome to My Awesome App!Text>
      <Button title="Go to Details" onPress={() => navigation.navigate('Details')} />
    View>
  );
};
const DetailsScreen = ({ route }) => {
  const { count } = route.params;
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Details ScreenText>
      <Text>Count: {count}Text>
    View>
  );
};
const Stack = createStackNavigator();
const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      Stack.Navigator>
    NavigationContainer>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    paddingHorizontal: 20,
    paddingVertical: 40,
    alignItems: 'center',
    justifyContent: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
});
export default App;

本地存储

为了保存用户数据,我们可以使用 AsyncStorage。

安装依赖

安装 @react-native-async-storage/async-storage:

expo install @react-native-async-storage/async-storage

使用本地存储

在 App.js 中使用 AsyncStorage 来保存和读取数据。

更新 HomeScreen 组件在 HomeScreen 中保存计数器的值到本地存储:

import AsyncStorage from '@react-native-async-storage/async-storage';
const HomeScreen = ({ navigation }) => {
  const [count, setCount] = useState(0);
  useEffect(() => {
    // 从本地存储读取计数器的值
    const getCount = async () => {
      try {
        const value = await AsyncStorage.getItem('@count');
        if (value !== null) {
          setCount(parseInt(value));
        }
      } catch (e) {
        console.error(e);
      }
    };
    getCount();
  }, []);
  const increment = () => {
    setCount(count + 1);
    // 将新的计数器值保存到本地存储
    AsyncStorage.setItem('@count', count.toString());
  };
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welcome to My Awesome App!Text>
      <Text>Count: {count}Text>
      <Button title="Increment" onPress={increment} />
      <Button title="Go to Details" onPress={() => navigation.navigate('Details', { count })} />
    View>
  );
};

推送通知

为了实现推送通知功能,我们可以使用 Expo 的推送服务。

配置推送通知

在 App.js 中注册设备并接收推送通知。

更新 App.js在 App 组件中注册设备并监听推送通知:

import React, { useState, useEffect } from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import * as Notifications from 'expo-notifications';
import AsyncStorage from '@react-native-async-storage/async-storage';
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});
const HomeScreen = ({ navigation }) => {
  const [count, setCount] = useState(0);
  useEffect(() => {
    const getCount = async () => {
      try {
        const value = await AsyncStorage.getItem('@count');
        if (value !== null) {
          setCount(parseInt(value));
        }
      } catch (e) {
        console.error(e);
      }
    };
    getCount();
  }, []);
  const increment = () => {
    setCount(count + 1);
    AsyncStorage.setItem('@count', count.toString());
  };
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welcome to My Awesome App!Text>
      <Text>Count: {count}Text>
      <Button title="Increment" onPress={increment} />
      <Button title="Go to Details" onPress={() => navigation.navigate('Details', { count })} />
    View>
  );
};
const DetailsScreen = ({ route }) => {
  const { count } = route.params;
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Details ScreenText>
      <Text>Count: {count}Text>
    View>
  );
};
const Stack = createStackNavigator();
const App = () => {
  const [expoPushToken, setExpoPushToken] = useState('');
  useEffect(() => {
    registerForPushNotificationsAsync().then(token => setExpoPushToken(token));
  }, []);
  useEffect(() => {
    const subscription = Notifications.addNotificationReceivedListener(notification => {
      console.log(notification);
    });
    const responseSubscription = Notifications.addNotificationResponseReceivedListener(response => {
      console.log(response);
    });
    return () => {
      subscription.remove();
      responseSubscription.remove();
    };
  }, []);
  const registerForPushNotificationsAsync = async () => {
    let token;
    if (Constants.isDevice) {
      const { status: existingStatus } = await Notifications.getPermissionsAsync();
      let finalStatus = existingStatus;
      if (existingStatus !== 'granted') {
        const { status } = await Notifications.requestPermissionsAsync();
        finalStatus = status;
      }
      if (finalStatus !== 'granted') {
        alert('Failed to get push token for push notification!');
        return;
      }
      token = (await Notifications.getExpoPushTokenAsync()).data;
      console.log(token);
    } else {
      alert('Must use physical device for Push Notifications');
    }
    if (Platform.OS === 'android') {
      Notifications.setNotificationChannelAsync('default', {
        name: 'default',
        importance: Notifications.AndroidImportance.MAX,
        vibrationPattern: [0, 250, 250, 250],
        lightColor: '#FF231F7C',
      });
    }
    return token;
  };
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      Stack.Navigator>
    NavigationContainer>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    paddingHorizontal: 20,
    paddingVertical: 40,
    alignItems: 'center',
    justifyContent: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
});
export default App;

打包与发布打包应用

使用 Expo CLI 打包应用:

expo build:android
expo build:ios

这将生成 APK 文件或 IPA 文件,可以用于安装到设备上进行测试。

发布应用

expo login
expo publish