Создание мобильных приложений с использованием React Native и WordPress
Опубликовано: 2022-03-10Как веб-разработчики, вы могли подумать, что разработка мобильных приложений требует новой кривой обучения с другим языком программирования. Возможно, вам нужно добавить Java и Swift в свой набор навыков, чтобы начать работу с iOS и Android, и это может вас утомить.
Но в этой статье вас ждет сюрприз! Мы рассмотрим создание приложения электронной коммерции для iOS и Android с использованием платформы WooCommerce в качестве нашего бэкэнда. Это было бы идеальной отправной точкой для всех, кто хочет заняться нативной кроссплатформенной разработкой.
Краткая история кроссплатформенной разработки
На дворе 2011 год, и мы видим начало разработки гибридных мобильных приложений. Медленно появляются такие фреймворки, как Apache Cordova, PhoneGap и Ionic Framework. Все выглядит хорошо, и веб-разработчики охотно кодируют мобильные приложения, используя имеющиеся у них знания.
Однако мобильные приложения по-прежнему выглядели как мобильные версии веб-сайтов. Никаких нативных дизайнов, таких как материальный дизайн Android или плоский вид iOS. Навигация работала так же, как в Интернете, и переходы не были плавными. Пользователей не устраивали приложения, созданные с использованием гибридного подхода, и они мечтали о нативном интерфейсе.
Перенесемся в март 2015 года, и на сцене появится React Native. Разработчики могут создавать действительно нативные кроссплатформенные приложения, используя React, любимую библиотеку JavaScript для многих разработчиков. Теперь они могут легко изучить небольшую библиотеку в дополнение к тому, что они знают по JavaScript. Обладая этими знаниями, разработчики теперь ориентируются на Интернет, iOS и Android.
Кроме того, изменения, внесенные в код во время разработки, практически мгновенно загружаются на тестовые устройства! Раньше это занимало несколько минут, когда у нас была нативная разработка с помощью других подходов. Разработчики могут получать мгновенную обратную связь, которую они привыкли любить в веб-разработке.
Разработчики React более чем рады возможности использовать существующие шаблоны, которым они следовали, на новой платформе. На самом деле, они нацелены еще на две платформы с тем, что они уже очень хорошо знают.
Все это хорошо для фронтенд-разработки. Но какой у нас есть выбор для серверных технологий? Должны ли мы все еще изучать новый язык или фреймворк?
REST-API WordPress
В конце 2016 года WordPress выпустил долгожданный REST API для своего ядра и открыл двери для решений с несвязанными серверными частями.
Итак, если у вас уже есть веб-сайт WordPress и WooCommerce и вы хотите сохранить одни и те же предложения и профили пользователей на своем веб-сайте и в нативном приложении, эта статья для вас!
Предположения, сделанные в этой статье
Я проведу вас через использование вашего навыка WordPress для создания мобильного приложения с магазином WooCommerce с использованием React Native. В статье предполагается:
- Вы знакомы с различными API WordPress, по крайней мере, на начальном уровне.
- Вы знакомы с основами React.
- У вас есть готовый сервер разработки WordPress. Я использую Ubuntu с Apache.
- У вас есть устройство Android или iOS для тестирования с помощью Expo.
Что мы будем строить в этом уроке
Проект, который мы собираемся создать в этой статье, — это приложение для магазина модной одежды. Приложение будет иметь следующие функции:
- Страница магазина со списком всех товаров,
- Одна страница продукта с подробной информацией о выбранном товаре,
- Функция «Добавить в корзину»,
- Функция «Показать товары в корзине»,
- Функция «Удалить товар из корзины».
Эта статья призвана вдохновить вас на использование этого проекта в качестве отправной точки для создания сложных мобильных приложений с использованием React Native.
Примечание . Полное приложение можно посмотреть в моем проекте на Github и клонировать его .
Начало работы с нашим проектом
Мы начнем создавать приложение в соответствии с официальной документацией React Native. Установив Node в вашей среде разработки, откройте командную строку и введите следующую команду, чтобы глобально установить приложение Create React Native.
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
После этого вы можете отсканировать QR-код через приложение Expo или ввести указанный URL-адрес в строке поиска приложения. Это запустит базовое приложение «Hello World» на мобильном телефоне. Теперь мы можем редактировать App.js, чтобы вносить мгновенные изменения в приложение, работающее на телефоне.
Кроме того, вы можете запустить приложение на эмуляторе. Но для краткости и точности мы рассмотрим его запуск на реальном устройстве.
Далее давайте установим все необходимые пакеты для приложения с помощью этой команды:
npm install -s axios react-native-htmlview react-navigation react-redux redux redux-thunk
Настройка сайта WordPress
Поскольку эта статья посвящена созданию приложения React Native, мы не будем вдаваться в подробности создания сайта WordPress. Пожалуйста, обратитесь к этой статье о том, как установить WordPress на Ubuntu. Поскольку REST API WooCommerce требует HTTPS, убедитесь, что он настроен с помощью Let’s Encrypt. Пожалуйста, обратитесь к этой статье за практическим руководством.
Мы не создаем установку 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 и pop, похожие на стеки в структурах данных. Push означает, что мы добавляем новый экран в верхнюю часть стека навигации. 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 в 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, действия и редукторы
В Redux у нас есть три разные части:
- Магазин
Содержит все состояние всего вашего приложения. Единственный способ изменить состояние — отправить ему действие. - Действия
Простой объект, представляющий намерение изменить состояние. - Редукторы
Функция, которая принимает состояние и тип действия и возвращает новое состояние.
Эти три компонента Redux помогают нам достичь предсказуемого состояния всего приложения. Для простоты мы рассмотрим, как продукты извлекаются и сохраняются в магазине Redux.
Прежде всего, давайте посмотрим на код создания магазина:
let middleware = [thunk]; export default function configureStore() { return createStore( RootReducer, applyMiddleware(...middleware) ); }
Затем действие products отвечает за получение продуктов с удаленного веб-сайта.
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); }) }; }
Редуктор продуктов отвечает за возврат полезной нагрузки данных и за необходимость ее изменения.
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> ); } }
this.props.ProductAction.getProducts()
и this.props.products
возможны из-за mapStateToProps
и mapDispatchToProps
.
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 нативные стили обычно определяются на одной странице. Это похоже на 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;
- Экспо можно использовать для запуска проекта на смартфоне;
- Можно использовать существующие серверные технологии, такие как WordPress;
- Redux можно использовать для управления состоянием всего приложения;
- Веб-разработчики, особенно разработчики React, могут использовать эти знания для создания более крупных приложений.
Чтобы получить полное приложение, вы можете посетить мой проект на Github и клонировать его. Не стесняйтесь раскошелиться и улучшить его дальше. В качестве упражнения вы можете продолжить добавлять в проект дополнительные функции, такие как:
- Страница оформления заказа,
- Аутентификация,
- Сохранение данных корзины в AsyncStorage, чтобы закрытие приложения не очищало корзину.