首页 > 其他分享 >reactnative ignite App + wordpress後台CMS 詳細案例

reactnative ignite App + wordpress後台CMS 詳細案例

时间:2023-08-10 17:26:13浏览次数:52  
标签:ignite __ name App 詳細 PROJECT post type app

1.0 入門篇

WordPress-Plugin-Boilerplate-Tutorial 更为简洁的架构方案

React Native Elements开发环境 & 生成项目 & 虚拟机调试 & 本地生成APK档 & 虚拟机运行APK档

 

2.0 Ignite框架

 

Ignite是reactnative里最最齊全的軍火庫。

https://github.com/infinitered/ignite

 

3.0 ReactNative庫

 以下是常用的RN庫。一部份已在Ignite框架,但仍需自行安裝另一些常用庫。

已在Ignite框架:

Library Category Description
React Navigation Navigation 必需先讀doc。
MobX-State-Tree State Management 必需先讀doc。
MobX-React-Lite React Integration /
apisauce REST client 采用Wordpress做後台。所以用哪個api庫不重要。

自行安裝:

Library Category Description
react-native-sqlite-storage Persistence /
moment FormatDatetime /
react-native-vector-icons Icon Framework 常見icon集合

@react-navigation/material-top-tabs

react-native-tab-view

react-native-pager-view

UI Framework React Navigation Toptabs庫

@rneui/base

@rneui/themed

UI Framework /

react-native-chart-kit

react-native-svg

UI Chart Framework /

 

4.0 Quick Start & Build App

 4.1 創建項目

npx ignite-cli@latest new {PROJECT_NAME} --yes

  

4.2 更改icon image

{PROJECT_NAME}\ignite\templates\app-icon

npx ignite-cli generate app-icon android

  Build App icon。

 

4.3 更改啟動splash

{PROJECT_NAME}\ignite\templates\splash-screen

npx ignite-cli generate splash-screen FF0000

  build splash。

 

4.4 更改android app名稱

{PROJECT_NAME}\android\app\src\main\res\values\strings.xml

<resources>
    <string name="app_name">Smoke507</string>
</resources>

  app_name就是android app名稱

 

4.5 Build App

adb devices -l
npm bundle:android
cd android && gradlew assembleDebug && adb install %PROJECT_ROOT%\android\app\build\outputs\apk\debug\app-debug.apk

  1行: 檢查devices。2行: compile。3行: Build APK。

 

 

5.0 Ignite框架

5.1 Ignite結構

在{PROJECT_NAME}\app下的Ignite結構。

PATH Description Files
components  Ignite自帶的漂亮組件  
config  項目設置

config.base.ts,通用

config.dev.ts,開發環境

config.prod.ts,生產環境

i18n  國際化  
models  MobX-State-Tree的Store  
navigators  React Navigation的狀態流  
screens  APP視圖  
services

網絡層

數據持久化層

 
theme  Ignite自帶的主題  
utils  工具庫  

 

5.2 Navigators

npx ignite-cli generate navigator CounterNavigator

  用Generators自動生成。組件在{PROJECT_NAME}\ignite\app\navigators。

 

{PROJECT_NAME}\ignite\app\navigators\AppNavigator.tsx

import { CounterTopTabsNavigator, CounterTopTabsNavigatorParamList } from "./CounterTopTabsNavigator"

export type AppStackParamList = {
  CounterNavigator: NavigatorScreenParams<CounterTabParamList>
}

const AppStack = observer(function AppStack() {
  const {
    authenticationStore: { isAuthenticated },
  } = useStores()

  return (
    <Stack.Navigator
      initialRouteName='CounterNavigator'
    >
      <Stack.Screen name="CounterNavigator" component={CounterNavigator} />
    </Stack.Navigator>
  )
})

  在AppNavigator主組件,載入剛剛自己的CounterNavigator。

 

5.3 Screen 視圖

npx ignite-cli generate screen CounterHome

  用Generators自動生成。組件在{PROJECT_NAME}\ignite\app\screens。

 

{PROJECT_NAME}\ignite\app\navigators\CounterHomeScreen.tsx

import React, { FC } from "react"
import { observer } from "mobx-react-lite"
import { ViewStyle } from "react-native"
import { NativeStackScreenProps } from "@react-navigation/native-stack"
import { AppStackScreenProps } from "app/navigators"
import { Screen, Text } from "app/components"
// import { useNavigation } from "@react-navigation/native"
// import { useStores } from "app/models"

interface CounterHomeScreenProps extends NativeStackScreenProps<AppStackScreenProps<"CounterHome">> {}

export const CounterHomeScreen: FC<CounterHomeScreenProps> = observer(function CounterHomeScreen() {
  // Pull in one of our MST stores
  // const { someStore, anotherStore } = useStores()

  // Pull in navigation via hook
  // const navigation = useNavigation()
  return (
    <Screen style={$root} preset="scroll">
      <Text text="counterHome" />
    </Screen>
  )
})

const $root: ViewStyle = {
  flex: 1,
}

  Screen模版。所有數據都必需由Store映射渣染。

 

5.3.1 把新視圖 載入 Navigators

{PROJECT_NAME}\ignite\app\navigators\CounterNavigator.tsx

import { CounterHomeScreen } from "../screens"

export type CounterTabParamList = {
  CounterHome: undefined,
}

const Tab = createBottomTabNavigator<CounterTabParamList>()
export const CounterNavigator = () => {
  const { bottom } = useSafeAreaInsets()
  
  return (
    <Tab.Navigator
      screenOptions={{
        headerShown: false,
        tabBarHideOnKeyboard: true,
      }}
    >
      <Tab.Screen
        name="CounterHomeScreen"
        component={CounterHomeScreen}
        options={{
          tabBarLabel: translate("CounterNavigator.CounterHomeTab"),
          tabBarIcon: ({ focused }) => (
            <Icon name={focused ? "home" : "home-outline"} type="ionicon" color={focused && colors.tint} size={30} />
          ),
          unmountOnBlur: false,
        }}
      />
      
    </Tab.Navigator>
  )
}

  在Tab.Screen綁定CounterHomeScreen。注意,只有BottomTabNavigator才有unmountOnBlur強制轉頁刷新。

 

5.4 MobX-State-Tree

由於經常切換視圖,因此要保持數據的有效性,必需用MST做數據Store中心化。

SMT用了Factory模式。經由SmokeStore去生產和和管理DataObject。

因此,任何DataObject必需包括: Store & Self。

 

npx ignite-cli generate Counter

  創建Somke。

 

import { Instance, SnapshotIn, SnapshotOut, types } from "mobx-state-tree"
import { withSetPropAction } from "./helpers/withSetPropAction"

/**
 * Model description here for TypeScript hints.
 */
export const CounterModel = types
  .model("Counter")
  .props({})
  .actions(withSetPropAction)
  .views((self) => ({})) // eslint-disable-line @typescript-eslint/no-unused-vars
  .actions((self) => ({})) // eslint-disable-line @typescript-eslint/no-unused-vars

export interface Counter extends Instance<typeof CounterModel> {}
export interface CounterSnapshotOut extends SnapshotOut<typeof CounterModel> {}
export interface CounterSnapshotIn extends SnapshotIn<typeof CounterModel> {}
export const createCounterDefaultModel = () => types.optional(CounterModel, {})

  Somke模板。

Function Description
model 實体名稱
props 屬性鍵
views 返回屬性
actions 修改屬性

 

5.4.1 加載Smoke

{PROJECT_ROOT}\app\models\index.ts

export * from "./Counter"

  加載Smoke到index.ts

 

{PROJECT_ROOT}\app\models\RootStore.ts

import { Instance, SnapshotOut, types } from "mobx-state-tree"

import { CounterModel } from "./Counter"

/**
 * A RootStore model.
 */
export const RootStoreModel = types.model("RootStore").props({
  counter: types.optional(CounterModel, {} as any),
})

/**
 * The RootStore instance.
 */
export interface RootStore extends Instance<typeof RootStoreModel> {}
/**
 * The data of a RootStore.
 */
export interface RootStoreSnapshot extends SnapshotOut<typeof RootStoreModel> {}

  1. import SmokeModel,2. 加載SmokeModel到RootStoreModel。

 

5.4.2 創建SmokeStore

 {PROJECT_ROOT}\app\models\CounterStore.ts

npx ignite-cli generate CounterStore

  創建SomkeStore。

 

 

5.4.3 SmokeStore模版

import { Instance, SnapshotIn, SnapshotOut, flow, types } from "mobx-state-tree"
import { Counter, CounterModel } from "./Counter"
import { withSetPropAction } from "./helpers/withSetPropAction"
/**
 * Model description here for TypeScript hints.
 */
export const CounterStoreModel = types
  .model("CounterStore")
  .props({
    counters: types.array(CounterModel),
  })
  .actions(withSetPropAction)
  .views((store) => ({
    get items() {
      return store.counters
    },
  })) // eslint-disable-line @typescript-eslint/no-unused-vars
  .actions((store) => ({
    async fetchCounters() {
      
    },
    
    addCounter: flow(function * (counter: Counter) {

    }),
    
    removeCounter: flow(function * (counter: Counter) {

    }),
  })) // eslint-disable-line @typescript-eslint/no-unused-vars

export interface CounterStore extends Instance<typeof CounterStoreModel> {}
export interface CounterStoreSnapshotOut extends SnapshotOut<typeof CounterStoreModel> {}
export interface CounterStoreSnapshotIn extends SnapshotIn<typeof CounterStoreModel> {}
export const createCounterStoreDefaultModel = () => types.optional(CounterStoreModel, {})

  SmokeStore模版

1. import之前創建的SmokeModel

2. 創建 <array - CounterModel> counters

3. 所有actions操作,必而flow。

addCounter: flow(function * (counter: Counter) {
  var response = yield api.addCounter(counter)
  if (response.data.status == 'success') {
    counter.setRowid(response.data.post_id)
    store.counters.push(counter)
  }
  return response
}),

  用flow yield 取代 async await。 詳細可參考: https://mobx-state-tree.js.org/concepts/async-actions

 

5.4.4 加載SmokeStore

{PROJECT_ROOT}\app\models\index.ts
{PROJECT_ROOT}\app\models\RootStore.ts

在index.ts & RootStore.ts 加載 SmokeStore。

 

6.0 API Service

{PROJECT_ROOT}\app\services\api\api.ts

網絡層。

 

7.0 Screen 使用 MST Store

 {PROJETC_ROOT}\app\screens\CounterHomeScreen.tsx

import { useStores } from "app/models"

interface CounterHomeScreenProps extends NativeStackScreenProps<AppStackScreenProps<"CounterHome">> {}

export const CounterHomeScreen: FC<CounterHomeScreenProps> = observer(function CounterHomeScreen(_props) {
  const { counterStore } = useStores()
  useEffect(() => {
    ;(async function load() {
      counterStore.fetchCounters()
    })()
  }, [counterStore])
  
  return (
    <Screen preset="scroll" safeAreaEdges={["top"]}>
      {{ counterStore.items() }}
    </Screen>
  )
})

1. useStores() 載入 counterStore 

2. useEffect是React生命周期。用await call counterStore.fetchCounters()。

3. react會自動渣染 counterStore.items()。

 

8.0 Ignite總彙

1.0 Create ingite project
1.1 Change app_icon, app_name, app_splash
1.2 Build APK

2.0 Create Bottom Navigators

3.0 Create Screen
3.1 Import Screen to Navigators

4.0 MST
4.1 Create Smoke & SmokeStore
4.2 Import SmokeStore to Screen

5.0 Use MST on Screen

Quick start Ignite!

 

9.0 Wordpress Plugin

https://wppb.me/

創建wordpress plugin。

 CleanAPI就是自己創建的Plugin。用來生產優雅的後端API。

Plugin根目錄: {PROJECT_ROOT}\wp-content\plugins\clean-api\

 

9.1 WP-CPT 後台CMS

 https://generatewp.com/post-type/

用generatewp生成CPT源碼。這個是用來生成Wordpress CMS視圖。

 

{PRODUCT_ROOT}\wp-content\plugins\clean-api\public\classes\junkFoodDataCPT.php

<?php

new junkFoodDataCPT();

class junkFoodDataCPT {
  
  function __construct() {
    $this->post_type = 'junk_food_data';
    $this->post_name = 'Food Data';
    add_action( 'init', [$this, "custom_post_type_{$this->post_type}"] );
    add_filter( "manage_{$this->post_type}_posts_columns", [$this, "set_{$this->post_type}_columns"] );
    add_action( "manage_{$this->post_type}_posts_custom_column" , [$this, "set_{$this->post_type}_custom_column"], 10, 2 );
    add_action( 'admin_init', [$this, "set_{$this->post_type}_meta_boxes"], 2);
    add_action( 'edit_form_after_title', [$this, "set_{$this->post_type}_header"], 2);
  }

  public function custom_post_type_junk_food_data() {

    $labels = array(
      'name'                  => _x( $this->post_name, 'Post Type General Name', $this->post_type ),
      'singular_name'         => _x( $this->post_name, 'Post Type Singular Name', $this->post_type ),
      'menu_name'             => __( $this->post_name, $this->post_type ),
      'name_admin_bar'        => __( $this->post_name, $this->post_type ),
      'archives'              => __( 'Item Archives', $this->post_type ),
      'attributes'            => __( 'Item Attributes', $this->post_type ),
      'parent_item_colon'     => __( 'Parent Item:', $this->post_type ),
      'all_items'             => __( 'All Items', $this->post_type ),
      'add_new_item'          => __( 'Add New Item', $this->post_type ),
      'add_new'               => __( 'Add New', $this->post_type ),
      'new_item'              => __( 'New Item', $this->post_type ),
      'edit_item'             => __( 'Edit Item', $this->post_type ),
      'update_item'           => __( 'Update Item', $this->post_type ),
      'view_item'             => __( 'View Item', $this->post_type ),
      'view_items'            => __( 'View Items', $this->post_type ),
      'search_items'          => __( 'Search Item', $this->post_type ),
      'not_found'             => __( 'Not found', $this->post_type ),
      'not_found_in_trash'    => __( 'Not found in Trash', $this->post_type ),
      'featured_image'        => __( 'Featured Image', $this->post_type ),
      'set_featured_image'    => __( 'Set featured image', $this->post_type ),
      'remove_featured_image' => __( 'Remove featured image', $this->post_type ),
      'use_featured_image'    => __( 'Use as featured image', $this->post_type ),
      'insert_into_item'      => __( 'Insert into item', $this->post_type ),
      'uploaded_to_this_item' => __( 'Uploaded to this item', $this->post_type ),
      'items_list'            => __( 'Items list', $this->post_type ),
      'items_list_navigation' => __( 'Items list navigation', $this->post_type ),
      'filter_items_list'     => __( 'Filter items list', $this->post_type ),
    );
    $args = array(
      'label'                 => __( $this->post_name, $this->post_type ),
      'description'           => __( $this->post_name, $this->post_type ),
      'labels'                => $labels,
      'hierarchical'          => false,
      'public'                => true,
      'show_ui'               => true,
      'show_in_menu'          => true,
      'menu_icon'             => 'dashicons-portfolio',
      'menu_position'         => 5,
      'show_in_admin_bar'     => false,
      'show_in_nav_menus'     => true,
      'can_export'            => true,
      'has_archive'           => true,
      'exclude_from_search'   => false,
      'publicly_queryable'    => true,
      'capability_type'       => 'page',
      'show_in_rest'          => true,
    );
    register_post_type( $this->post_type, $args );
  }

  public function set_junk_food_data_columns($columns) {

  }

  public function set_junk_food_data_custom_column($column_id, $post_id) {

  }
  
  public function set_junk_food_data_meta_boxes() {

  }
  
  public function set_junk_food_data_header() {

  }
}

 CPT必需是Class Object。

 

{PROJECT_ROOT}\wp-content\plugins\clean-api\public\class-clean-api-public.php

public function __construct( $plugin_name, $version ) {

  $this->plugin_name = $plugin_name;
  $this->version = $version;

  require_once("classes/junkFoodDataCPT.php");
}

 把剛剛創建的junkFoodDataCPT.php,加載到class-clean-api-public.php。

 

9.2 API Service

 {PROHECT_ROOT}\wp-content\plugins\clean-api\public\classes\apiV1.php

add_action( 'rest_api_init', function () {
  register_rest_route( $this->plugin_name.'/v1', '/get-smoke/all', array(
    'methods' => 'POST',
    'callback' => 'get_smoke_all',
  ));
});

add_action( 'rest_api_init', function () {
  register_rest_route( $this->plugin_name.'/v1', '/save-smoke', array(
    'methods' => 'POST',
    'callback' => 'save_smoke',
    'args' => array(
      'dt' => array('required' => true),
      'user' => array('required' => true),
      'area' => array('required' => true),
      'noItem' => array('required' => true),
    ),
  ));
});

function get_smoke_all($data) {
  $posts = get_posts(
    array(
      'post_status' => 'publish',
      'numberposts' => -1,
      'post_type'   => 'smoke_data',
      'meta_key'    => 'dt',
      'orderby'     => 'meta_value',
      'order'       => 'DESC',
    )
  );
  $posts2 = array();
  foreach ($posts as $k1 => $v1) {
    $post = array('rowid' => $v1->ID);
    foreach (array('dt', 'user', 'area', 'noItem') as $v2) {
      $post[$v2] = get_post_meta($v1->ID, $v2, true);
      if ($v2 == 'noItem') {
        $post[$v2] = (int)$post[$v2];
      }
    }
    $posts2[] = $post;
  }
  
  if ($posts2) {
    return wp_send_json(array('status' => 'success', 'data' => $posts2), 200);
  }
  else {
    return wp_send_json(array('status' => 'fail', 'error' => $posts2), 200);
  }
}

function save_smoke($data) {
  $post = array(
    'post_status' => 'publish',
    'post_type' => 'smoke_data',
    'meta_input' => array(
      'dt' => $data['dt'],
      'user' => $data['user'],
      'area' => $data['area'],
      'noItem' => $data['noItem'],
    ),
  );
  $res = wp_insert_post($post);
  
  if ($res) {
    return wp_send_json(array('status' => 'success', 'post_id' => $res), 200);
  }
  else {
    return wp_send_json(array('status' => 'fail', 'error' => $res), 200);
  }
}

1. register_rest_route可用前置器,設置需required哪些args。

2. 所有dataobject都是用WP Post type來存取。

 

{PROJECT_ROOT}\wp-content\plugins\clean-api\public\class-clean-api-public.php

public function __construct( $plugin_name, $version ) {

  $this->plugin_name = $plugin_name;
  $this->version = $version;

  require_once("classes/apiV1.php");
  require_once("classes/junkFoodDataCPT.php");
}

  把剛剛創建的apiV1.php,加載到class-clean-api-public.php。

 

9.3 Wordpress User Management

 用Wordpress自帶的user group來管理用戶。

 

标签:ignite,__,name,App,詳細,PROJECT,post,type,app
From: https://www.cnblogs.com/chenkuang/p/17585313.html

相关文章

  • 虚拟试衣间app开发
      虚拟试衣间app开发功能  随着科技的不断发展,虚拟试衣间app已经成为了越来越多人购物的选择。通过这些应用程序,用户可以在家中或任何地方轻松试穿衣服,而无需走出家门。虚拟试衣间app的开发可以帮助商家提高客户满意度,并为他们提供更多的销售机会。  虚拟试衣间app的......
  • sqlite3 db "delete from apps where title='Typora';"&&killall Dock
    command+shift+G进入访达前往->输入/private/var/folders 搜索:com.apple.dock.launchpad  仔细看了下执行的命令就发现了sqlite3db这个东西,可以深入了解下  ......
  • 使用SRS+第三方APP实现推流拉流学习
    一、下载杏林推流APP二、APP设置推流地址进行一些自定义的参数配置,设置好之后点击进入直播。进入直播后,点击开始推流按钮进行推流。三、SRS服务启动和手机APP推流1.启动srs服务使用docker执行如下命令启动srs:dockerrun--rm-it-p1935:1935-p1985:1985-p8080:8080--envCA......
  • tomcat10 javaweb webapp jstl的maven依赖库配置
    1.在pom.xml中配置,可能不是最新版,在idea中可能会报黄线,但是可以正常使用<dependencies><!--https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api--><dependency><groupId>jakarta.servlet</groupId>......
  • Spring cloud智慧工地源码(项目端+监管端+数据大屏+APP)
    【智慧工地PC项目端功能总览】一.项目人员管理包括:信息管理、信息采集、证件管理、考勤管理、考勤明细、工资管理、现场统计、WIFI教育、工种管理、分包商管理、班组管理、项目管理。1.信息管理:头像、姓名、性别、身份证、进场时间、分包单位、劳务工种、项目履历、是否零工、计......
  • 【看表情包学Linux】初识文件描述符 | 虚拟文件系统 (VFS) 初探 | 系统传递标记位 | O
    爆笑教程《看表情包学Linux》......
  • 【Azure ACR+App Service】ACR WebHook请求App Service时遇见 401 Unauthorized
    问题描述AppService支持从ACR中直接拉取镜像,并且可以配置持续部署(ContinuousDeployment),它是通过在ACR中添加一个Webhook,然后发送POST请求到<yourappservicename>.scm.chinacloudsites.cn/api/registry/webhook接口,触发AppService从ACR中pull新的image。但是,为什么会......
  • 痞子衡嵌入式:AppCodeHub - 一站网罗恩智浦MCU应用程序
    近日,恩智浦官方隆重上线了应用程序代码中心(ApplicationCodeHub,简称ACH),这是恩智浦MCUXpresso软件生态的一个重要组成部分。痞子衡之所以要如此激动地告诉大家这个好消息,是因为ACH并不是又一个恩智浦官方githubprojectsite那么简单而已,且听痞子衡细细道来:ACHgithub......
  • 物业管理APP开发在实际生活中能带来哪些便利?
    随着社会的不断发展和生活方式的变化,物业管理成为了一个日益重要的领域。为了更好地满足居民的需求,提升物业管理的效率和质量,物业管理APP的开发应运而生。这类移动应用程序不仅为物业公司提供了更便捷的管理工具,也为居民提供了更方便的服务和沟通渠道。在实际生活中,物业管理app开发......
  • ABC245E Wrapping Chocolate [线段树二分]
    也许更好的阅读体验\(\mathcal{Description}\)\(n\)个物品有长和宽,\(m\)个盒子也有长和宽,一个盒子最多可以装一个物品,问\(n\)个物品能否都放进盒子,物品和盒子不能旋转\(\mathcal{Solution}\)先离散化长和宽,将物品和盒子按照长从大到小排序考虑到当前物品时将所有长大于等于当......