1. 程式人生 > >可能是React Native比較好用的框架?

可能是React Native比較好用的框架?

前言

最近公司開始重寫我們歷史悠久的iOS應用。由於iOS和安卓都是N手專案,所以重寫。前端技術選擇了React Native。雖然我之前用React Native開發過,但是是和原生混編。對於搭建一個React Native並不是特別熟悉。經過幾天的摸索自認為弄出來個還算不太差的框架,分享出來大家一起學習。只說實戰,沒有原理分析。這是程式碼地址DLReactNativeArchitecture沒有Demo的都是流氓。

內容結構

  • JavaScript程式碼檢測
    • ESlint在VS Code下的配置
  • 頁面管理
    • 底部導航
    • 頁面導航
    • 切換導航
  • 資料管理
    • 全域性資料管理
    • 網路請求錯誤管理

JavaScript程式碼檢測

我個人認為這個應該是React Native開發的標配了。從我個人開發來看,在寫頁面的時候經常忘記引用元件,這個時候並不會有提示,當你運行了專案模擬器才會告訴你錯誤,必須回去修改程式碼,再次執行,降低了開發效率。在程式碼編寫的時候就提示書寫錯誤顯得非常重要。

ESlint在VS Code下的配置

eslint.png

  • 在VS Code下載ESlint外掛
  • npm i eslint-config-rallycoding babel-eslint --save-dev
  • 在專案根目錄建立.eslintrc拷貝下方配置(在rules中自行配置)
{
    "extends": "eslint-config-rallycoding",
    "parser": "babel-eslint",
    "rules": {
        "semi": 0    
    }
}
複製程式碼

頁面管理

用React Native開發,如果想實現像iOS原生UITabBarControllerUINavigationController對頁面的導航管理,只能用TabBarIOSNavigatorIOS,但是這兩個元件都不支援Android(天殺的安卓)。官網推薦了使用

react-native-navigationreact-navigation,我在自己的專案中選擇了react-navigation,因為✨更多。(寫著寫著發現react-navigation3.0出來了)

底部導航

tabbar_navigator.png

// 在routes檔案中
import {
    createBottomTabNavigator,
    createAppContainer
} from 'react-navigation'

import HomePage from '../pages/Home'
import MessagePage from '../pages/Message'
import ProfilePage from '../pages/Profile'

import styles from '../styles'

function _renderTabbarIcon(icon) {
	return <Image source={icon} style={styles.tabBarIcon} />
}

const tabarIcons = {
    Home: {
        render: focused => {
            return focused
                ? _renderTabbarIcon(require('../images/tabbar_home_selected.png'))
                : _renderTabbarIcon(require('../images/tabbar_home.png'))
        }
    }
}

const tabBarStack = createBottomTabNavigator({
    Home: {
        screen: HomePage,
        navigationOptions: {
            tabBarLabel: '首頁'
        }   
    },
    Message: {
        screen: MessagePage,
        navigationOptions: {
            tabBarLabel: '資訊'
        }
    },
    Profile: {
        screen: ProfilePage,
        navigationOptions: {
            tabBarLabel: '我的'
        }
    }
}, {
    defaultNavigationOptions: ({ navigation }) => ({
        tabBarIcon: ({ focused }) => {
            const { routeName } = navigation.state
            return tabarIcons[routeName].render(focused)
        }
    }),
    tabBarOptions: {
        activeTintColor: '#6699ff',
        inactiveTintColor: '#333'
    }
})

export default createAppContainer(tabBarStack)

// 在App.js檔案中
import TabbarStack from './src/routes'

export default class App extends Component {
    render() {
        return <TabbarStack />
    }
}
複製程式碼
頁面導航

home_detail.png
home_detail_hide_tabbar.png
第一張圖是從Home頁面跳轉到Home Detail頁面不隱藏Tabbar,第二張則是隱藏Tabbar。在程式碼中我會使用 ~注意~來提示。寫注意的地方都大家可以多注意一下^^,不太通順!

// 在routes檔案中
const HomeStack = createStackNavigator({
    Home: {
       screen: HomePage,
       navigationOptions: {
           title: '首頁'
       }
    },
    HomeDetail: {
       screen: HomeDetailPage,
       navigationOptions: {
           title: '詳情'
       } 
    }
}, {
    navigationOptions: {
        headerStyle: {
            backgroundColor: "#fff",
            borderBottomWidth: 0
        },
        headerTintColor: "#333",
        headerBackTitle: null         // ~注意~ 這個地方是隱藏返回按鈕文字的
    }
})

HomeStack.navigationOptions = ({ navigation }) => {  // ~注意~ 如果想實現隱藏Tabbar的功能要呼叫這個方法
    let tabBarVisible = true
    if (navigation.state.index > 0) {
        tabBarVisible = false
    }
    return {
        tabBarVisible
    }
}
const TabBarStack = createBottomTabNavigator({
    Home: {
        screen: HomeStack,
        navigationOptions: {
            tabBarLabel: '首頁'
        }   
    }
})
複製程式碼
切換導航

這個主要是用於APP廣告頁面到Tabbar導航的跳轉,或者是登入頁面到Tabbar導航的跳轉。

switch_navigator.png

// 在routes檔案中
const switchStack = createSwitchNavigator({
    Launch: {
        screen: LaunchPage,
        navigationOptions: {
            header: null
        }
    },
    Tabbar: {
        screen: TabBarStack
    }
}, {
    initialRouteName: 'Launch'
})

export default createAppContainer(switchStack)
複製程式碼

資料管理

在資料管理中我使用了react-redux, axios, redux-axios-middleware以及react-native-dropdownalert。因為涉及的檔案較多,不一一列舉。其中我想說幾點,一個使用者private_token的新增,還有就是用axios進行網路請求的時候GET和POST新增引數的區別。

全域性資料管理

fetch_data.png

// 在store/reducers/message.js檔案
export default function reducer(state = initialState, action) {
    switch (action.type) {
        case FETCH_MESSAGE_LIST: 
            return {
                ...state,
                loading: true,
                list: [],
            }
        case FETCH_MESSAGE_LIST_SUCCESS:
            return {
                ...state,
                loading: false,
                list: action.payload.data.items
            }
        case FETCH_MESSAGE_LIST_FAIL:
            return {
                ...state,
                loading: false,
                error: action.error.message
            }
        case REMOVE_MESSAGE_WITH_ID: {
            const { itemId } = action.payload
            return {
                ...state,
                list: state.list.filter(l => l.id !== itemId)
            }
        }
        default: 
            return state
    }
}
複製程式碼
全域性錯誤管理

在這個配置中要注意的就是,user_token的新增。因為AsyncStorage.getItem是非同步方法,所以success也要變成非同步方法。

// App.js檔案中
const middlewareConfig = {
    interceptors: {
        request: [
            {
                success: async function (_, req) {
                    // const token = await AsyncStorage.getItem('user_token')
                    const newReq = {
                        ...req,
                        headers: {
                            ...req.headers,
                            common: {
                                ...req.headers.common,
                                // Authorization: token
                            },
                        }
                    }
                    return newReq
                }
            }
        ],
        response: [
            {
                success: function (_, res) {
                    return res
                },
                error: function (_, error) {
                    DropDownHolder.getDropDown().alertWithType('error', 'Error', error.message)
                    return Promise.reject(error)
                }
            }
        ]
    }
}
複製程式碼

最後

更多詳細的程式碼大家可以看原始碼DLReactNativeArchitecture。不知道這個對大家有沒有幫助,本人水平有限。寫文章條理也不是太清晰,還有些名字寫得也不是特別合適。如果大家對程式碼,對文章有什麼問題,建議可以在評論留言。大家一起學習,一起進步。