使用 React Native 和 WordPress 構建移動應用程序

已發表: 2022-03-10
快速總結↬ WordPress 可以作為您下一個本機應用程序的出色後端平台,尤其是在內容驅動或在線商店的情況下。 在本文中,您將了解使用 React Native 和 WordPress 構建移動應用程序的基礎。

作為 Web 開發人員,您可能認為移動應用程序開發需要使用另一種編程語言進行全新的學習曲線。 也許需要將 Java 和 Swift 添加到您的技能組合中才能在 iOS 和 Android 上運行,這可能會讓您陷入困境。

但這篇文章讓你大吃一驚! 我們將著眼於使用 WooCommerce 平台作為後端構建適用於 iOS 和 Android 的電子商務應用程序。 對於任何願意進入原生跨平台開發的人來說,這將是一個理想的起點。

跨平台開發簡史

現在是 2011 年,我們看到了混合移動應用程序開發的開始。 Apache Cordova、PhoneGap 和 Ionic Framework 等框架慢慢出現。 一切看起來都不錯,Web 開發人員正急切地利用他們現有的知識編寫移動應用程序。

然而,移動應用程序看起來仍然像網站的移動版本。 沒有像 Android 的材料設計或 iOS 的平面外觀這樣的原生設計。 導航的工作方式與網絡類似,並且過渡並不流暢。 用戶對使用混合方法構建的應用程序並不滿意,他們夢想著原生體驗。

快進到 2015 年 3 月,React Native 出現了。 開發人員能夠使用 React 構建真正的原生跨平台應用程序,這是許多開發人員最喜歡的 JavaScript 庫。 他們現在可以輕鬆地在他們所知道的 JavaScript 知識之上學習一個小型庫。 有了這些知識,開發人員現在瞄準了 Web、iOS 和 Android。

跳躍後更多! 繼續往下看↓

此外,在開發過程中對代碼所做的更改幾乎會立即加載到測試設備上! 當我們通過其他方法進行本地開發時,這通常需要幾分鐘。 開發人員能夠享受他們過去喜歡 Web 開發的即時反饋。

React 開發人員非常高興能夠將他們遵循的現有模式完全用於新平台。 事實上,他們的目標是另外兩個平台,他們已經非常了解。

這對前端開發都是有好處的。 但是我們對後端技術有什麼選擇呢? 我們還需要學習新的語言或框架嗎?

WordPress REST API

2016 年底,WordPress 將期待已久的 REST API 發佈到其核心,並為具有分離後端的解決方案打開了大門。

因此,如果您已經擁有 WordPress 和 WooCommerce 網站,並希望在您的網站和本機應用程序中保留完全相同的產品和用戶資料,那麼本文適合您!

本文中的假設

我將引導您使用您的 WordPress 技能使用 React Native 構建一個帶有 WooCommerce 商店的移動應用程序。 文章假設:

  • 您至少在初學者水平上熟悉不同的 WordPress API。
  • 你熟悉 React 的基礎知識。
  • 您已準備好 WordPress 開發服務器。 我使用 Ubuntu 和 Apache。
  • 你有一個 Android 或 iOS 設備來測試 Expo。

我們將在本教程中構建什麼

我們將通過本文構建的項目是一個時尚商店應用程序。 該應用程序將具有以下功能:

  • 列出所有產品的商店頁面,
  • 單個產品頁面,包含所選項目的詳細信息,
  • “加入購物車”功能,
  • “在購物車中顯示商品”功能,
  • “從購物車中刪除商品”功能。

本文旨在啟發您以這個項目為起點,使用 React Native 構建複雜的移動應用程序。

注意對於完整的應用程序,您可以訪問我在 Github 上的項目並克隆它

開始我們的項目

我們將根據官方 React Native 文檔開始構建應用程序。 在您的開發環境中安裝 Node 後,打開命令提示符並鍵入以下命令以全局安裝 Create React Native App。

 npm install -g create-react-native-app

接下來,我們可以創建我們的項目

create-react-native-app react-native-woocommerce-store

這將創建一個新的 React Native 項目,我們可以使用 Expo 進行測試。

接下來,我們需要在我們想要測試的移動設備上安裝 Expo 應用程序。 它適用於 iOS 和 Android。

安裝 Expo 應用程序後,我們可以在我們的開發機器上運行 npm start。

 cd react-native-woocommerce-store npm start
通過 Expo 命令行啟動一個 React Native 項目。 (大預覽)

之後,您可以通過 Expo 應用程序掃描二維碼或在應用程序的搜索欄中輸入給定的 URL。 這將在移動設備中運行基本的“Hello World”應用程序。 我們現在可以編輯 App.js 以對手機上運行的應用程序進行即時更改。

或者,您可以在模擬器上運行該應用程序。 但為了簡潔和準確,我們將介紹在實際設備上運行它。

接下來,讓我們使用以下命令安裝應用程序所需的所有軟件包:

 npm install -s axios react-native-htmlview react-navigation react-redux redux redux-thunk

設置 WordPress 網站

由於本文是關於創建 React Native 應用程序的,因此我們不會詳細介紹如何創建 WordPress 站點。 請參閱這篇關於如何在 Ubuntu 上安裝 WordPress 的文章。 由於 WooCommerce REST API 需要 HTTPS,請確保使用 Let's Encrypt 進行設置。 請參閱本文以獲取操作指南。

我們不會在 localhost 上創建 WordPress 安裝,因為我們將在移動設備上運行該應用程序,而且還需要 HTTPS。

成功設置 WordPress 和 HTTPS 後,我們可以在網站上安裝 WooCommerce 插件。

將 WooCommerce 插件安裝到我們的 WordPress 安裝中。 (大預覽)

安裝並激活插件後,按照嚮導繼續設置 WooCommerce 商店。 嚮導完成後,單擊“返回儀表板”。

您將受到另一個提示的歡迎。

將示例產品添加到 WooCommerce。 (大預覽)

單擊“讓我們開始”以“添加示例產品”。 這將節省我們創建自己的產品以在應用程序中顯示的時間。

常量文件

要從 WooCommerce REST API 加載我們商店的產品,我們需要在我們的應用程序中放置相關的密鑰。 為此,我們可以有一個constans.js文件。

首先創建一個名為“src”的文件夾,並在其中創建子文件夾,如下所示:

在 constans 文件夾中創建文件“Constants.js”。 (大預覽)

現在,讓我們為 WooCommerce 生成密鑰。 在 WordPress 儀表板中,導航到 WooCommerce → 設置 → API → 密鑰/應用程序,然後單擊“添加密鑰”。

接下來創建一個名為 React Native 的只讀鍵。 將 Consumer Key 和 Consumer Secret 複製到constants.js文件中,如下所示:

 const Constants = { URL: { wc: 'https://woocommerce-store.on-its-way.com/wp-json/wc/v2/' }, Keys: { ConsumerKey: 'CONSUMER_KEY_HERE', ConsumerSecret: 'CONSUMER_SECRET_HERE' } } export default Constants;

從 React 導航開始

React Navigation 是一個在不同屏幕之間導航的社區解決方案,並且是一個獨立的庫。 它允許開發人員只用幾行代碼設置 React Native 應用程序的屏幕。

React Navigation 中有不同的導航方法:

  • 堆,
  • 轉變,
  • 標籤,
  • 抽屜,
  • 和更多。

對於我們的應用程序,我們將結合使用StackNavigationDrawerNavigation在不同的屏幕之間導航。 StackNavigation類似於瀏覽器歷史記錄在網絡上的工作方式。 我們使用它是因為它為標題和標題導航圖標提供了一個界面。 它具有類似於數據結構中的堆棧的推送和彈出。 Push 意味著我們在 Navigation Stack 的頂部添加了一個新屏幕。 Pop 從堆棧中刪除一個屏幕。

代碼顯示StackNavigation實際上將DrawerNavigation在其內部。 它還獲取標題樣式和標題按鈕的屬性。 我們將抽屜式導航按鈕放在左側,將購物車按鈕放在右側。 抽屜按鈕打開和關閉抽屜,而購物車按鈕將用戶帶到購物車屏幕。

 const StackNavigation = StackNavigator({ DrawerNavigation: { screen: DrawerNavigation } }, { headerMode: 'float', navigationOptions: ({ navigation, screenProps }) => ({ headerStyle: { backgroundColor: '#4C3E54' }, headerTintColor: 'white', headerLeft: drawerButton(navigation), headerRight: cartButton(navigation, screenProps) }) }); const drawerButton = (navigation) => ( <Text style={{ padding: 15, color: 'white' }} onPress={() => { if (navigation.state.index === 0) { navigation.navigate('DrawerOpen') } else { navigation.navigate('DrawerClose') } } }> ( <Text style={{ padding: 15, color: 'white' }} onPress={() => { navigation.navigate('CartPage') }} > <EvilIcons name="cart" size={30} /> {screenProps.cartCount} </Text> );  const StackNavigation = StackNavigator({ DrawerNavigation: { screen: DrawerNavigation } }, { headerMode: 'float', navigationOptions: ({ navigation, screenProps }) => ({ headerStyle: { backgroundColor: '#4C3E54' }, headerTintColor: 'white', headerLeft: drawerButton(navigation), headerRight: cartButton(navigation, screenProps) }) }); const drawerButton = (navigation) => ( <Text style={{ padding: 15, color: 'white' }} onPress={() => { if (navigation.state.index === 0) { navigation.navigate('DrawerOpen') } else { navigation.navigate('DrawerClose') } } }> ( <Text style={{ padding: 15, color: 'white' }} onPress={() => { navigation.navigate('CartPage') }} > <EvilIcons name="cart" size={30} /> {screenProps.cartCount} </Text> );

另一方面, DrawerNavigation提供了側抽屜,它允許我們在 Home、Shop 和 Cart 之間導航。 DrawerNavigator列出了用戶可以訪問的不同屏幕,即主頁、產品頁面、產品頁面和購物車頁面。 它還有一個屬性可以使用 Drawer 容器:單擊漢堡菜單時打開的滑動菜單。

 const DrawerNavigation = DrawerNavigator({ Home: { screen: HomePage, navigationOptions: { title: "RN WC Store" } }, Products: { screen: Products, navigationOptions: { title: "Shop" } }, Product: { screen: Product, navigationOptions: ({ navigation }) => ({ title: navigation.state.params.product.name }), }, CartPage: { screen: CartPage, navigationOptions: { title: "Cart" } } }, { contentComponent: DrawerContainer }); 
#
左:主頁( homepage.js )。 右圖:打開的抽屜 (DrawerContainer.js)。

將 Redux Store 注入 App.js

由於我們在這個應用程序中使用 Redux,我們必須將商店注入到我們的應用程序中。 我們在Provider組件的幫助下做到了這一點。

 const store = configureStore(); class App extends React.Component { render() { return ( <Provider store={store}> <ConnectedApp /> </Provider> ) } }

然後,我們將擁有一個ConnectedApp組件,以便我們可以在標題中包含購物車計數。

 class CA extends React.Component { render() { const cart = { cartCount: this.props.cart.length } return ( <StackNavigation screenProps={cart} /> ); } } function mapStateToProps(state) { return { cart: state.cart }; } const ConnectedApp = connect(mapStateToProps, null)(CA);

Redux Store、Action 和 Reducer

在 Redux 中,我們有三個不同的部分:

  1. 店鋪
    保存整個應用程序的整個狀態。 改變狀態的唯一方法是向它發送一個動作。
  2. 行動
    一個簡單的對象,表示改變狀態的意圖。
  3. 減速機
    接受狀態和動作類型並返回新狀態的函數。

Redux 的這三個組件幫助我們為整個應用程序實現可預測的狀態。 為簡單起見,我們將研究如何在 Redux 存儲中獲取和保存產品。

首先,讓我們看一下創建商店的代碼:

 let middleware = [thunk]; export default function configureStore() { return createStore( RootReducer, applyMiddleware(...middleware) ); }

接下來,產品操作負責從遠程網站獲取產品。

 export function getProducts() { return (dispatch) => { const url = `${Constants.URL.wc}products?per_page=100&consumer_key=${Constants.Keys.ConsumerKey}&consumer_secret=${Constants.Keys.ConsumerSecret}` return axios.get(url).then(response => { dispatch({ type: types.GET_PRODUCTS_SUCCESS, products: response.data } )}).catch(err => { console.log(err.error); }) }; }

products reducer負責返回數據的payload以及是否需要修改。

 export default function (state = InitialState.products, action) { switch (action.type) { case types.GET_PRODUCTS_SUCCESS: return action.products; default: return state; } }

展示 WooCommerce 商店

products.js文件是我們的商店頁面。 它基本上顯示來自 WooCommerce 的產品列表。

 class ProductsList extends Component { componentDidMount() { this.props.ProductAction.getProducts(); } _keyExtractor = (item, index) => item.id; render() { const { navigate } = this.props.navigation; const Items = ( <FlatList contentContainerStyle={styles.list} numColumns={2} data={this.props.products || []} keyExtractor={this._keyExtractor} renderItem={ ({ item }) => ( <TouchableHighlight style={{ width: '50%' }} onPress={() => navigate("Product", { product: item })} underlayColor="white"> <View style={styles.view} > <Image style={styles.image} source={{ uri: item.images[0].src }} /> <Text style={styles.text}>{item.name}</Text> </View> </TouchableHighlight> ) } /> ); return ( <ScrollView> {this.props.products.length ? Items : <View style={{ alignItems: 'center', justifyContent: 'center' }}> <Image style={styles.loader} source={LoadingAnimation} /> </View> } </ScrollView> ); } }

由於mapStateToPropsmapDispatchToPropsthis.props.ProductAction.getProducts()this.props.products是可能的。

產品列表屏幕。 (大預覽)

mapStateToPropsmapDispatchToProps

State 是 Redux 存儲,Dispatch 是我們觸發的操作。 這兩個都將作為組件中的道具公開。

 function mapStateToProps(state) { return { products: state.products }; } function mapDispatchToProps(dispatch) { return { ProductAction: bindActionCreators(ProductAction, dispatch) }; } export default connect(mapStateToProps, mapDispatchToProps)(ProductsList);

風格

在 React 中,Native 樣式通常定義在同一頁面上。 它類似於 CSS,但我們使用camelCase屬性而不是連字符屬性。

 const styles = StyleSheet.create({ list: { flexDirection: 'column' }, view: { padding: 10 }, loader: { width: 200, height: 200, alignItems: 'center', justifyContent: 'center', }, image: { width: 150, height: 150 }, text: { textAlign: 'center', fontSize: 20, padding: 5 } });

單一產品頁面

此頁麵包含所選產品的詳細信息。 它向用戶顯示產品的名稱、價格和描述。 它還具有“添加到購物車”功能。

單一產品頁面。 (大預覽)

購物車頁面

此屏幕顯示購物車中的項目列表。 該操作具有函數getCartaddToCartremoveFromCart 。 減速器同樣處理這些動作。 動作的識別是通過 actionTypes 完成的——描述存儲在單獨文件中的動作的常量。

 export const GET_PRODUCTS_SUCCESS = 'GET_PRODUCTS_SUCCESS' export const GET_PRODUCTS_FAILED = 'GET_PRODUCTS_FAILED'; export const GET_CART_SUCCESS = 'GET_CART_SUCCESS'; export const ADD_TO_CART_SUCCESS = 'ADD_TO_CART_SUCCESS'; export const REMOVE_FROM_CART_SUCCESS = 'REMOVE_FROM_CART_SUCCESS';

這是CartPage組件的代碼:

 class CartPage extends React.Component { componentDidMount() { this.props.CartAction.getCart(); } _keyExtractor = (item, index) => item.id; removeItem(item) { this.props.CartAction.removeFromCart(item); } render() { const { cart } = this.props; console.log('render cart', cart) if (cart && cart.length > 0) { const Items = <FlatList contentContainerStyle={styles.list} data={cart} keyExtractor={this._keyExtractor} renderItem={({ item }) => <View style={styles.lineItem} > <Image style={styles.image} source={{ uri: item.image }} /> <Text style={styles.text}>{item.name}</Text> <Text style={styles.text}>{item.quantity}</Text> <TouchableOpacity style={{ marginLeft: 'auto' }} onPress={() => this.removeItem(item)}><Entypo name="cross" size={30} /></TouchableOpacity> </View> } />; return ( <View style={styles.container}> {Items} </View> ) } else { return ( <View style={styles.container}> <Text>Cart is empty!</Text> </View> ) } } }

如您所見,我們使用FlatList來遍歷購物車項目。 它接受一個數組並創建一個要在屏幕上顯示的項目列表。

#
左:有商品時的購物車頁面。 右:購物車頁面為空時。

結論

您可以在app.json文件中配置應用的名稱和圖標等信息。 應用 npm 安裝 exp 後即可發布。

總結:

  • 我們現在有了一個不錯的帶有 React Native 的電子商務應用程序;
  • Expo可用於在智能手機上運行項目;
  • 可以使用WordPress等現有的後端技術;
  • Redux 可用於管理整個應用程序的狀態;
  • Web 開發人員,尤其是 React 開發人員可以利用這些知識來構建更大的應用程序。

對於完整的應用程序,您可以訪問我在 Github 上的項目並克隆它。 隨意分叉並進一步改進它。 作為練習,您可以繼續在項目中構建更多功能,例如:

  • 結帳頁面,
  • 驗證,
  • 將購物車數據存儲在 AsyncStorage 中,以便關閉應用程序不會清除購物車。