- 作者:老汪软件技巧
- 发表时间: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