使用 React Native 和 WordPress 构建移动应用程序
已发表: 2022-03-10作为 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 应用程序扫描二维码或在应用程序的搜索栏中输入给定的 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 商店。 向导完成后,单击“返回仪表板”。
您将受到另一个提示的欢迎。
单击“让我们开始”以“添加示例产品”。 这将节省我们创建自己的产品以在应用程序中显示的时间。
常量文件
要从 WooCommerce REST API 加载我们商店的产品,我们需要在我们的应用程序中放置相关的密钥。 为此,我们可以有一个constans.js
文件。
首先创建一个名为“src”的文件夹,并在其中创建子文件夹,如下所示:
现在,让我们为 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 中有不同的导航方法:
- 堆,
- 转变,
- 标签,
- 抽屉,
- 和更多。
对于我们的应用程序,我们将结合使用StackNavigation
和DrawerNavigation
在不同的屏幕之间导航。 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 });
将 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 中,我们有三个不同的部分:
- 店铺
保存整个应用程序的整个状态。 改变状态的唯一方法是向它发送一个动作。 - 行动
一个简单的对象,表示改变状态的意图。 - 减速机
接受状态和动作类型并返回新状态的函数。
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> ); } }
由于mapStateToProps
和mapDispatchToProps
, this.props.ProductAction.getProducts()
和this.props.products
是可能的。
mapStateToProps
和mapDispatchToProps
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 } });
单一产品页面
此页面包含所选产品的详细信息。 它向用户显示产品的名称、价格和描述。 它还具有“添加到购物车”功能。
购物车页面
此屏幕显示购物车中的项目列表。 该操作具有函数getCart
、 addToCart
和removeFromCart
。 减速器同样处理这些动作。 动作的识别是通过 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 中,以便关闭应用程序不会清除购物车。