preface

React Native lets you write Native mobile apps for Android and iOS using only JavaScript. Many of you have heard of the current popular cross-platform front-end Flutter, ReactNative and Weex. The Flutter it’s probably using the DART language and the cross end, and then a new grammar that might have to be learned again for the front end. ReactNative and Weex itself are through the front-end React and Vue syntax, as long as these two frameworks are very good to use. ReactNative is designed on the same principle as React, using declarative component mechanisms to build a rich user interface. The only difference is that the style is written a little bit differently and the rest of it feels the same as React.

Environment set up

Because it is a cross-end project that requires android environment and iOS development environment, I just built the Android environment myself at present.

The dependencies that must be installed are Node, JDK, and Android Studio. Here about Node and JDK and Android environment is not an introduction, online are some, the official website is also some.

(Note the node version, JDK version and android SDK version)

  • node >=12
  • JDK 1.8 (required)
  • Android SDK Platform 29

Website ReactNative android environment building (official documents) : ReactNative. Cn/docs/enviro…

Initialize the project

Initialize the project with the NPX installed by node

npx react-native init AwesomeProject
Copy the code

AwesomeProject is the name of the project. You can also initialize the project using react-native CLI, but this must be installed globally with react-native CLI. We initialize the highest version of react-Native by default. We can also specify the version of the project React-Native by –version x.xx.x.

Also, we can use –template to specify the template to download for the project initialization. For example, the official website has a typescript version

npx react-native init AwesomeTSProject --template react-native-template-typescript
Copy the code

Since I have developed several react-Native APP development projects, each time I create a new project, I copy the dependencies of the previous project to initialize the project, which feels very troublesome. Therefore, I also manually build an initialization template according to the basic dependencies I need.

NPM package address: www.npmjs.com/package/rea…

Github: github.com/jetBn/react…

This template is used to configure some basic esLint and project dependencies, such as using Ant’s React-Native UI framework, network requests, upload files, and so on. The specific dependencies and file directory information are as follows:

Main entry file

The main entry for the project is index.js, but we have many pages on our page, so we use React Navigation to follow the tabbar, subpages, etc.

React Navigation

The main way to create a TabBar is to use @React-navigation /bottom-tabs in React Navigation. There are detailed instructions in the official document of the package, so I will not list them here. I believe this document will not be difficult for us, even though it is in English.

This is where the custom tabBar is recorded

import React, { useEffect, UseState} from 'react' import {createBottomTabNavigator} from '@react navigation/bottom-tabs' useState} from 'react' import {createBottomTabNavigator} from '@react navigation/bottom-tabs Const MyTabBar=({state, descriptors, descriptors, descriptors) navigation }) => { const focusedOptions = descriptors[state.routes[state.index].key].options if (focusedOptions tabBarVisible = = = false) {return null} return (main tabbar section layout < / / the View style = {{/ / overflow: 'hidden', height: calc(50, 'height'), flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', borderTopColor: '#F4F4F4', backgroundColor: '#FFFFFF', borderTopWidth: 1, paddingBottom: isIPhoneX() ? 16:0, // Determine whether the value is isIPhoneX position: // Here we get the tab.screen loop I defined in tab.navigator {state.routes. Map ((route, index) => { const { options } = descriptors[route.key] // console.log(options.tabBarIcon()) Const label = options.tabBarLabel! Const label = options.tabBarLabel! == undefined ? options.tabBarLabel : options.title ! == undefined ? options.title : Name const isFocused = state. Index === index // Const onPress = () => {const event = navigation.emit({ type: 'tabPress', target: route.key }) if (! isFocused && ! => {navigation. Emit ({type:) => {navigation. Emit ({type:) => < span style = "text-align: right;  'tabLongPress', target: Return (<TouchableOpacity accessibilityRole="button") accessibilityStates={isFocused ? ['selected'] : []} accessibilityLabel={options.tabBarAccessibilityLabel} testID={options.tabBarTestID} onPress={onPress} onLongPress={onLongPress} key={index} style={{ // flex: , width: calc(150), justifyContent: 'center', alignItems: 'center' }}> {options.tabBarIcon({ focused: isFocused })} <Text style={{ color: isFocused ? '#222222' : '#777777', fontSize: sT(11), textAlign: 'center', fontWeight: '500', marginTop: Calc (6)}}> {label} </Text> </TouchableOpacity>)})} // <View style={{width: calc(83), height: calc(83), position: 'absolute', left: '50%', marginLeft: -calc(41), bottom: calc(5) }}> <TouchableOpacity activeOpacity={1} onPress={() => { getToken().then((res) => { if (res === '') { navigation.navigate('Login') } else { showImgPikcer() } }) }}> <Image style={{ width: '100%', height: '100%' }} source={require('.. /.. /assets/images/home_tab_scanning.png')} /> </TouchableOpacity> </View> </View> ) } const Tabs = () => { return ( <Tab.Navigator tabBar={(props) => <MyTabBar {... {{labelStyle: {bottom: 5}, keyboardHidesTabBar: props} />} True, allowFontScaling: false}}> < tab. Screen name="Home" Component ={Home} options={{tabBarLabel: TabBarIcon: ({focus}) => {if (focus) {return (<Image source={require('.. /.. /assets/images/home_tab_file_s.png')} /> ) } else { return ( <Image source={require('.. /.. /assets/images/home_tab_file_n.png')} /> ) } } }} /> <Tab.Screen name="Mine" component={Mine} options={{ tabBarLabel: TabBarIcon: ({focus}) => {if (focus) {return (<Image source={require('.. /.. /assets/images/home_tab_user_s.png')} /> ) } else { return ( <Image source={require('.. /.. /assets/images/home_tab_user_n.png')} /> ) } } }} /> </Tab.Navigator> ) } export default TabsCopy the code

In this case, we only need to introduce the tab.js file into the route stack of index.js in the router folder of my template, and the effect picture is as follows.

The basic way to create pages is to introduce the @React-navigation /stack package in index.js where I use a separate file to write all of our page file configurations in the main folder.

So I’ve configured the webView page here and in the Props configuration for Screen I can configure the information for the page like the color of the title bar, display the title bar to the left, display the title bar to the right, etc., and I can also customize the title bar.

Network request encapsulation

In the project, I mainly used AXIos as the encapsulation of network request, which mainly implemented the interceptor of network request and response. It mainly realizes that the parameters in the network request are encapsulated into form form data by QS, and the global judgment whether the data is returned normally in the response result.

Const service = axios.create({baseURL: BASE_URL, // API BASE_URL timeout: 60000, // Request timeout header: { 'Content-Type':'application/x-www-form-urlencoded', }}) / / request interceptor service. The interceptors. Request. Use (async config = > {the if (config. The method = = = 'post') {config. Data = Qs.stringify(config.data)} config.headers["token"] = await getToken() // Netinfo.fetch ().then(state => {if(! {duration: toast.durations.LONG, position: 0, shadow: true, animation: true, hideOnPress: true, delay: 1000 }) } }); console.log(config.headers) return config }, error => { console.log('error', Error) Promise. Reject (error)}) / / response interceptor service. The interceptors. Response. Use (response = > { console.log(response.data.status) if(typeof response.data.status ! =='undefined' && response.data.status ! == 200000500){ return response.data.data } if(typeof response.data ==='object' && typeof response.data.status === 'undefined') { return response.data } // console.log(response.status) Toast.show(response.data.message) return Promise.reject(response.data) }, error => { if (error.response.status == 401) { } return Promise.reject(error) } ) export default serviceCopy the code

File upload encapsulation

Because I used Axios for the network request. At that time, I was confused after uploading the file and didn’t know how to do it. After all, there is still a difference between mobile phone and web page. Because Axios is also used on web pages. Because the files selected on the web page are uploaded using blobs. On my mobile phone, the files I choose are always the file path beginning with file or just return to the file path. In addition, the back-end API also receives the corresponding file to upload through the way of uploading the file in the web page.

I was wondering how this would translate into the same form as the front end web page, and finally FOUND a fetch package rN-fetch -blob, which supports file upload and download.

Github: github.com/joltup/rn-f…

I used the Promise method to encapsulate image file uploading and other methods

Dark mode adaptation

Because I’m using React Navigation so I also directly use the hook method (useColorScheme) provided in the react-Native Appearance package and use this package to provide the overall routing component of the AppearanceProvider package.

  1. Defining a topicconfigThe configuration information is in the config file, and then corresponds todarkwithlightMode color configuration, then I need to passuseColorSchemeIs directly corresponding to thisObjectThe field ofkeyOk, the configuration file is as follows

Page use

2. Manual Settings and automatic Settings configuration, if when we set the automatic follow system is ok, directly through thishookWe can get the corresponding color information, but if the user sets manual then we have to reevaluate. What I’m going to do is set it tokeyI’ll put it in the cache, and then I’llindex.jsThat is, through the main entrancehooktheuseEffectGet the cachekeyDetermine whether it is automatic or manual. If it is manual, obtain the correspondingvaluethroughAppearance.setMethod to set our theme color.

Appearance here is imported via react-native Appearance.

Page adaptation

Because it is cross-terminal and mobile phone is also a variety of this page ADAPTS JS is essential, otherwise in different mobile phone will produce page bug display is different. Mainly through the benchmark design draft as a fixed parameter and then through the API to get the device screen width and height, divide to get the corresponding value and then multiply the value set.

There is landscape adaptation, in fact, is to determine whether it is landscape and then by setting the width of the benchmark to the height of the screen, so that the horizontal over the page can also be adapted.

conclusion

The main thing in React-Native development is that setting up the environment can be time-consuming. The writing method is basically the same as that in React, except for the writing of style, native mainly uses the form of style and uses the form of Object. If I write too much, it will be separated from the writing of CSS. I wrote too much react-native style before. And then you go back and write CSS and it’s always going to be written as native Object.

In addition, the react-Native now uses the third package without manual link, now will be automatically associated, so it is very convenient to use. Sometimes it’s buggy, so try not to use third-party packages from long ago. 😂 😂