news 2026/10/26 10:06:25

android-dev - react-native

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
android-dev - react-native

React Native 参考(TypeScript)

项目结构

src/ ├── app/ │ ├── App.tsx # Root component, providers │ ├── navigation/ # React Navigation stacks + types │ └── store/ # RTK store setup ├── features/ │ └── home/ │ ├── api/ # RTK Query endpoints │ ├── components/ # Screen-specific components │ ├── hooks/ # Feature-level custom hooks │ ├── screens/ # Screen components │ ├── store/ # Zustand slice or RTK slice │ └── types.ts # Feature types ├── shared/ │ ├── components/ # Design system components │ ├── hooks/ # Shared hooks │ ├── theme/ # Colors, typography, spacing constants │ └── utils/ # Utilities └── services/ ├── api/ # Axios/fetch client + interceptors └── storage/ # MMKV wrapper

导航设置(React Navigation v7)

exporttypeRootStackParamList={Auth:undefined;Home:undefined;Detail:{id:string};Settings:undefined;};exporttypeRootStackScreenProps<TextendskeyofRootStackParamList>=NativeStackScreenProps<RootStackParamList,T>;constStack=createNativeStackNavigator<RootStackParamList>();exportconstRootNavigator=()=>{constisLoggedIn=useAuthStore((s)=>s.isLoggedIn);return(<Stack.Navigator screenOptions={{headerShown:false}}>{isLoggedIn?(<><Stack.Screen name="Home"component={HomeScreen}/><Stack.Screen name="Detail"component={DetailScreen}/></>):(<Stack.Screen name="Auth"component={AuthScreen}/>)}</Stack.Navigator>);};

状态管理(Zustand 和 React Query)

// Client state — Zustand// Do not persist bearer or refresh tokens in AsyncStorage/plain MMKV.// Store secrets with a platform-backed module such as react-native-keychain// or expo-secure-store, and persist only non-sensitive UI state here.interfaceAuthState{isLoggedIn:boolean;setLoggedIn:(value:boolean)=>void;logout:()=>void;}exportconstuseAuthStore=create<AuthState>()(persist((set)=>({isLoggedIn:false,setLoggedIn:(value)=>set({isLoggedIn:value}),logout:()=>set({isLoggedIn:false}),}),{name:'auth-ui-storage',storage:createJSONStorage(()=>mmkvStorage)}));// Keep tokens outside persisted app state.constgetSecureToken=()=>Keychain.getGenericPassword().then((r)=>(r?r.password:null));constsaveSecureToken=(token:string)=>Keychain.setGenericPassword('auth',token);constclearSecureToken=()=>Keychain.resetGenericPassword();// Server state — React QueryexportconstuseItems=()=>useQuery({queryKey:['items'],queryFn:itemsApi.getAll,staleTime:5*60*1000,// 5 minutes});exportconstuseRefreshItems=()=>useMutation({mutationFn:itemsApi.refresh,onSuccess:()=>queryClient.invalidateQueries({queryKey:['items']}),});

屏幕模式

typeHomeScreenProps=RootStackScreenProps<'Home'>;exportconstHomeScreen:FC<HomeScreenProps>=({navigation})=>{const{data:items,isLoading,isError,refetch}=useItems();if(isLoading)return<LoadingView/>;if(isError)return<ErrorView onRetry={refetch}/>;return(<SafeAreaView style={styles.container}><FlatList data={items}keyExtractor={(item)=>item.id}renderItem={({item})=>(<ItemCard item={item}onPress={()=>navigation.navigate('Detail',{id:item.id})}/>)}ListEmptyComponent={<EmptyView/>}refreshControl={<RefreshControl refreshing={isLoading}onRefresh={refetch}/>}/></SafeAreaView>);};

API 客户端(带拦截器的 Axios)

constapiClient=axios.create({baseURL:Config.API_BASE_URL,timeout:10_000,headers:{'Content-Type':'application/json'},});// Auth token injectionapiClient.interceptors.request.use(async(config)=>{consttoken=awaitgetSecureToken();if(token)config.headers.Authorization=`Bearer${token}`;returnconfig;});// Token refresh on 401apiClient.interceptors.response.use((res)=>res,async(error:AxiosError)=>{if(error.response?.status===401){constnewToken=awaitrefreshToken();if(newToken){awaitsaveSecureToken(newToken);useAuthStore.getState().setLoggedIn(true);returnapiClient(error.config!);}awaitclearSecureToken();useAuthStore.getState().logout();}returnPromise.reject(error);});

API 响应验证(Zod)

constItemSchema=z.object({id:z.string(),title:z.string(),description:z.string().optional(),createdAt:z.string().datetime(),});constItemsResponseSchema=z.array(ItemSchema);typeItem=z.infer<typeofItemSchema>;constgetItems=async():Promise<Item[]>=>{const{data}=awaitapiClient.get('/items');returnItemsResponseSchema.parse(data);// throws ZodError on invalid shape};

关键依赖

{"dependencies":{"react-native":"0.74.x","@react-navigation/native":"^7.0.0","@react-navigation/native-stack":"^7.0.0","@tanstack/react-query":"^5.45.0","zustand":"^4.5.4","axios":"^1.7.2","zod":"^3.23.8","react-native-keychain":"^8.2.0","react-native-mmkv":"^2.12.2","react-native-safe-area-context":"^4.10.1","react-native-screens":"^3.32.0"},"devDependencies":{"typescript":"^5.4.5","@testing-library/react-native":"^12.5.1","msw":"^2.3.1","jest":"^29.7.0"}}

新架构(无桥)笔记

  • 在android/gradle.properties中启用新架构:newArchEnabled=true
  • 对于原生模块使用 TurboModules;避免使用传统的 NativeModules API
  • 使用 Fabric 定制原生视图
  • 始终启用 Hermes JS 引擎进行测试

性能提示

  • 在renderItem/ 列表项组件上使用useCallback和memo
  • FlatList的windowSize、initialNumToRender、maxToRenderPerBatch已调优
  • 在 JSX 中避免使用匿名内联函数
  • InteractionManager.runAfterInteractions用于导航后进行大量工作
  • react-native-reanimated用于 60fps 动画(在 UI 线程上运行)

测试

describe('HomeScreen',()=>{it('shows items when query succeeds',async()=>{server.use(http.get(`${API_URL}/items`,()=>HttpResponse.json([{id:'1',title:'Test Item'}])));const{getByText}=render(<QueryClientProvider client={testQueryClient}><HomeScreen navigation={mockNavigation}route={mockRoute}/></QueryClientProvider>);expect(awaitfindByText('Test Item')).toBeTruthy();});});
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 10:02:12

AI落地从能用走向好用:Agent编排、模型部署与工程化避坑

早上一开机就被各种群聊和社区话题轮番刷屏&#xff0c;2026-09-29这一天&#xff0c;AI相关的讨论密度明显比前几周高了一大截。如果说前两年的关键词是“卷参数、卷榜单”&#xff0c;今年的风向已经完全变了&#xff1a;Agent、工程化、可靠性、模型部署、垂直场景落地成了真…

作者头像 李华
网站建设 2026/10/26 9:55:24

OpenAlice的Trading-as-Git:本地量化Agent架构与风控闭环拆解

告别盲目实盘暴仓&#xff1a;深入拆解 OpenAlice 的 Trading-as-Git 本地量化 Agent 架构与风控闭环我见过太多人倒在实盘第一周。不是策略不赚钱&#xff0c;而是亏在工程问题&#xff1a;信号延迟、成交价偏离、参数被意外改动、事件日志缺失、复盘时完全想不起当时为什么下…

作者头像 李华
网站建设 2026/10/26 9:44:22

MATLAB男女声音识别实战:特征提取与分类器全流程

简介&#xff1a;面向音频处理与机器学习初学者的MATLAB男声女声识别项目&#xff0c;基于GUI图形界面完成性别分类。资源共五个文件&#xff0c;包含三段分别用于训练和测试的男女声音频、一个GUI布局文件以及一份完整M源码&#xff0c;压缩包仅1.42MB&#xff0c;轻量易部署。…

作者头像 李华