“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!

preface

Recently, the company is preparing to develop a scanning code billing type of micro channel small program, time is tight, urgent task. The first reaction is to open the small program open platform to view the development documents, oh huo, the official components are too few, do you want to write it by hand? Through multi-party research, it is understood that Uniapp and Taro are the most popular small program development frameworks in the market. Since the company’s technology stack is fully developed using React Hooks + TS, Taro is the natural choice of framework.

Introduction of Taro

Taro is an open cross-end cross-framework solution that supports the use of React/Vue/Nerv frameworks to develop applications such as wechat/JD/Baidu/Alipay/Bytedance/QQ Mini Program/H5 / RN. At present, the upper end of the market has a variety of forms, such as Web, React Native, wechat small program and other terminals are popular. When business requirements are required to perform on different ends at the same time, the cost of writing multiple sets of code for different ends is obviously very high, and the ability to write only one set of code to be able to adapt to multiple ends is extremely necessary.

Installation and use

The Taro project is based on node. Make sure you have a relatively new node environment (>=12.0.0). It is recommended to use the node version management tool NVM to manage nodes.

CLI Tool Installation

First, you need to use NPM or yarn global install @tarojs/cli, or use NPX directly:

Install the CLI using NPM
npm install -g @tarojs/cli

# OR Use Yarn to install the CLI
yarn global add @tarojs/cli

# OR install CNPM, use CNPM to install CLI
cnpm install -g @tarojs/cli
Copy the code

NPM 5.2+ can also use NPX to create a template project without a global installation:

 npx @tarojs/cli init taro_init_template
Copy the code

For convenience, it is recommended to create a template project using NPX directly

Run & start the project

# yarn
 yarn dev:weapp
 yarn build:weapp

# npm script
 npm run dev:weapp
 npm run build:weapp

# Global installation only
 taro build --type weapp --watch
 taro build --type weapp

# NPX users can also use it
 npx taro build --type weapp --watch
 npx taro build --type weapp

# Watch Also enables compression
$ set NODE_ENV=production && taro build --type weapp --watch # Windows
$ NODE_ENV=production taro build --type weapp --watch # Mac
Copy the code

The above is the compilation command of wechat small program, and other small program compilation can be viewed in the package.json folder under the project folder

Run the small program, you will find an additional dist folder in the project directory, open the wechat developer tool, log in with your own wechat signal, click + in the small program interface, import the project, define the project name by yourself, select the folder dist folder under the newly created template project, AppId can temporarily use the test number oh, Later you can register one for development use.

[Sitemap Index Information] According to the Sitemap rule [0], the current page [pages/index/index] will be indexed

Json => setting => checkSiteMap

{
	"miniprogramRoot": "dist/"."projectname": "taro_template"."description": "taro_template"."appid": "touristappid"."setting": {
		"urlCheck": true."es6": false."postcss": false."preloadBackgroundData": false."minified": false."newFeature": true."autoAudits": false."coverView": true."showShadowRootInWxmlPanel": false."scopeDataCheck": false."useCompilerModule": false.// Add it here
		"checkSiteMap":false
	},
	"compileType": "miniprogram"."simulatorType": "wechat"."simulatorPluginLibVersion": {},
	"condition": {}}Copy the code

Quickly create new page & Add TabBar

Taro Create –name [page name] can quickly generate a new page file in the pages directory of the current project and fill in the base code. It is a powerful tool to improve development efficiency. Add a page and configure app.config.ts

App.config. ts Complete configuration

export default {
  pages: [
    "pages/index/index"."pages/setting/setting".// "pages/login/login"].subpackages: [{root: "pages/login/".pages: [
        "login"]}],window: {
    backgroundTextStyle: "light".navigationBarBackgroundColor: "#fff".navigationBarTitleText: "WeChat".navigationBarTextStyle: "black"
  },
  tabBar: {
    list: [{pagePath: "pages/index/index".text: "Home page".iconPath: "assets/images/tab_index.png".selectedIconPath: "assets/images/tab_index_active.png"
      },
      {
        pagePath: "pages/setting/setting".text: "Personal center".iconPath: "assets/images/tab_setting.png".selectedIconPath: "assets/images/tab_setting_active.png"}].color: "#BFBFBF".selectedColor: "#1296DB".backgroundColor: "#fff".borderStyle: "white"}};Copy the code

The app.config.ts file has subpackages added to it. Here’s how this configuration works

Subpackages subcontract

When the small program is started, the main package will be downloaded and the page in the main package will be started by default. When the user enters a page in the subpackage, the client will download the corresponding subpackage and display it after the download is complete.

At present, the size of small program subcontract has the following restrictions:

  • The subcontract size of the whole small program shall not exceed 20M
  • The size of a single subcontract or main package cannot exceed 2M

Note: Subcontracting cannot be used as tabbar pages. Subcontracting pages can be added to subpackages and removed from Pages

routing

Taro.switchTab(option)

Go to the tabBar page and close all other non-Tabbar pages

Taro.reLaunch(option)

Close all pages and open a page in the application

Taro.redirectTo(option)

The current page is closed and a page in the application is displayed. However, jumping to the Tabbar page is not allowed.

Taro.navigateTo(option)

Keep the current page and go to a page in the application. But you can’t jump to the Tabbar page. Use Taro. NavigateBack to return to the original page. The page stack in the applet is up to ten layers.

Taro.navigateBack(option)

Close the current page and return to the previous page or multilevel page. You can use getCurrentPages to get the current stack of pages and determine how many layers to return.

For details about how to use routes, see the official document.

Request encapsulates Taro. Request

Defining a unified state
export const HTTP_STATUS = {
    SUCCESS: 200.CREATED: 201.ACCEPTED: 202.CLIENT_ERROR: 400.AUTHENTICATE: 301.FORBIDDEN: 403.NOT_FOUND: 404.SERVER_ERROR: 500.BAD_GATEWAY: 502.SERVICE_UNAVAILABLE: 503.GATEWAY_TIMEOUT: 504
  }

  export const REFRESH_STATUS = {
    NORMAL: 0.REFRESHING: 1.NO_MORE_DATA: 2
  }
Copy the code
Define an error uniform output method
import { formatTime } from ".. /utils/common"
/ * * * *@param {string} Name Indicates the incorrect name *@param {string} Action Description of the error action *@param {string} Info Error message, usually */ returned by fail
// eslint-disable-next-line
export const logError = (name: string, action: string, info? :string | object ) = > {
  if(! info) { info ='empty'
  }
  let time = formatTime(new Date())
  console.error(time, name, action, info)
  if (typeof info === 'object') {
    info = JSON.stringify(info)
  }
}
Copy the code
Define the request. Ts
import Taro from '@tarojs/taro'
import { HTTP_STATUS } from './status'
import { logError } from './error'
import { baseUrl } from './baseUrl'
import { checkLogin } from "./auth"

export default {
  baseOptions(params, method = 'GET') {
    let { url, data } = params
    let contentType = 'application/json'
    contentType = params.contentType || contentType
    type OptionType = {
      url: string, data? :object | string, method? :any.header: object.// mode: string,
      success: any.error: any.xhrFields: object,}const setCookie = (res: {
      cookies: Array<{
        name: string,
        value: string,
        expires: string,
        path: string
      }>,
      header: {
        'Set-Cookie': string}}) = > {
      if (res.cookies && res.cookies.length > 0) {
        let cookies = Taro.getStorageSync('cookies') | |' ';
        res.cookies.forEach((cookie, index) = > {
          // Windows wechat developer tool returns cookie format with name and value, on MAC it is just a string
          if (cookie.name && cookie.value) {
            cookies += index === res.cookies.length - 1 ? `${cookie.name}=${cookie.value}; expires=${cookie.expires}; path=${cookie.path}` : `${cookie.name}=${cookie.value}; `
          } else {
            cookies += `${cookie}; `}}); Taro.setStorageSync('cookies', cookies)
      }
      // if (res.header && res.header['Set-Cookie']) {
      // Taro.setStorageSync('cookies', res.header['Set-Cookie'])
      // }
    }
    const option: OptionType = {
      url: url.indexOf('http')! = = -1 ? url : baseUrl + url,
      data: data,
      method: method,
      header: {
        'content-type': contentType,
        // Add the request header
        cookie: Taro.getStorageSync('cookies')},// mode: 'cors',
      xhrFields: { withCredentials: true },
      success(res) {
        console.log('res', res)
        setCookie(res)
        if (res.statusCode === HTTP_STATUS.NOT_FOUND) {
          return logError('api'.'Requested resource does not exist')}else if (res.statusCode === HTTP_STATUS.BAD_GATEWAY) {
          return logError('api'.'There is a server problem')}else if (res.statusCode === HTTP_STATUS.FORBIDDEN) {
          return logError('api'.'No access')}else if (res.statusCode === HTTP_STATUS.AUTHENTICATE) {
          Taro.clearStorage()
          // Go to the login page
          checkLogin()
          return logError('api'.'Please login first')}else if (res.statusCode === HTTP_STATUS.SUCCESS) {
          return res.data
        }
      },
      error(e) {
        logError('api'.'Request interface problem', e)
      }
    }
    // eslint-disable-next-line
    return Taro.request(option)
  },
  get(url, data? :object) {
    let option = { url, data }
    return this.baseOptions(option)
  },
  post: function (url, data? :object, contentType? :string) {
    let params = { url, data, contentType }
    return this.baseOptions(params, 'POST')},put(url, data? :object) {
    let option = { url, data }
    return this.baseOptions(option, 'PUT')},delete(url, data? :object) {
    let option = { url, data }
    return this.baseOptions(option, 'DELETE')}}Copy the code
Define the baseUrl. Ts
export const baseUrl = 'http://172.36.0.26:3000'
Copy the code
Define the API. Ts
import request from "./request"

export const getDetail = (params):Promise<any> = > {return request.get('/url', params)
}
Copy the code
Component
  const getDetail = () = >{
    api.getDetail({
      data: 1232
    }).then((res) = >{
      console.log(res)
    })
  }
Copy the code

Dva integration use

React state Management library: Redux, Dva, Mobx… This building uses Dva to build. Finally, the reason why WE choose Dva is completely to try new things, because we have been using Redux in previous projects, and we must know the complexity of Redux. You can also try Mobx. Mobx is arguably the cleanest of these libraries.

Of course, useContext() in hooks is also a solution for sharing state between components.

The installation
npm install --save dva-core dva-loading
npm install --save redux react-redux redux-thunk redux-logger
Copy the code

New SRC/utils/dva. Ts

// src/utils/dva.ts
import {create } from 'dva-core';
// import {createLogger } from 'redux-logger';
import createLoading from 'dva-loading';

let app: {use: (arg0: any) = > void; model: (arg0: any) = > any; start: () = > void; _store: any; getStore: () = > any; dispatch: any};
let store: {dispatch: any};
let dispatch: any;
let registered: boolean;

function createApp(opt: {models: any[]; initialState: any }) {

  // Redux logs, refer to redux-logger
  // opt.onAction = [createLogger()];
  app = create(opt);
  app.use(createLoading({}));


  if(! registered) opt.models.forEach((model: any) = > app.model(model));
  registered = true;
  app.start();

  store = app._store;
  app.getStore = () = > store;

  dispatch = store.dispatch;

  app.dispatch = dispatch;
  return app;
}

export default {
  createApp,
  getDispatch() {
    return app.dispatch;
  },
  getStore() { // This is a method to get the Store from a non-component file
    returnapp.getStore(); }};Copy the code
Add the Models folder

Models is dedicated to managing your own data in a unified manner

models/index.ts


import { GlobalModelState } from "./setting/types"
import setting from "./setting/index"


const models:Array<GlobalModelState> = [
    setting
]

export default models
Copy the code

models/setting/index.ts

import * as types from "./types";

const setting: types.GlobalModelState = {
  namespace: "setting".state: {
    userInfo: {}},// Modify the data in state
  reducers: {
    setUserInfo(state, { data }) {
      console.log(data);
      return {
        ...state,
        userInfo: data.userInfo }; }}// Modify the data in state after the asynchronous operation
  // effects: {
  // *changeName({ payload }, { put, call }) {
  // // Call triggers asynchrony
  // // let data = yield call("/api", payload);

  // // put Triggers the action
  // yield put({
  // type: "saveName",
  // data: {
  // name: "asynchronously modified ",
  / /},
  / /});
  // yield console.log("run");
  / /},
  // },
};

export default setting;
Copy the code
Entrance to the integration

Change the entry file app.ts to app. TSX, and introduce Provider, DVA, and Models.

import { Component, useEffect } from "react";
import { View, Text } from "@tarojs/components";
import "./app.scss";

// React-redux must be used here or an error will be reported
import { Provider } from "react-redux";

import dva from "./utils/dva";

import models from "./models";

/ / integration dva
const dvaApp = dva.createApp({
  initialState: {},
  models,
  enableLog: false
});
const store = dvaApp.getStore();

const App: React.FC = ({ children }): JSX.Element => {

  return <Provider store={store}>{children}</Provider>;
};

export default App;


Copy the code

Get data from the Store (useSelector)

const userInfo = useSelector(state= > state.setting.userInfo).nickName
Copy the code

Modifying data in a Store (useDispatch)

  dispatch({
    type:"setting/setUserInfo".data:{
      userInfo
    }
  })
Copy the code

Page adaptation problem

By default, Taro is automatically converted to designWidth: 750. If the UI is given a 375 width, you can change it to config => **index.js **

designWidth: 750.deviceRatio: {
    640: 2.34 / 2.750: 1.828: 1.81 / 2.375: 2
  },
Copy the code

Of course, just changing the above part is not enough. Run the project at this time, and you will find that the taro UI component style becomes very large. What? The component is magnified twice? Do not panic, as follows can be configured

yarn add postcss-px-scale
Copy the code
const config = {
  projectName: "taro_template".date: "2021-6-23".designWidth: 750.deviceRatio: {
    640: 2.34 / 2.750: 1.828: 1.81 / 2.375: 2
  },
  sourceRoot: "src".outputRoot: "dist".plugins: [].defineConstants: {},
  copy: {
    patterns: [].options: {}},framework: "react".mini: {
    postcss: {
      pxtransform: {
        enable: true.config: {}},url: {
        enable: true.config: {
          limit: 1024 // Set the upper limit of the conversion size}},cssModules: {
        enable: false.// The default is false, or true if you need to use CSS Modules
        config: {
          namingPattern: "module".// The conversion mode is global/module
          generateScopedName: "[name]__[local]___[hash:base64:5]"}},// Add configuration here
      "postcss-px-scale": {
        enable: true.config: { scale: 0.5.units: "rpx".includes: ["taro-ui"]}},},},h5: {
    publicPath: "/".staticDirectory: "static".esnextModules: ['taro-ui'].postcss: {
      autoprefixer: {
        enable: true.config: {}},cssModules: {
        enable: false.// The default is false, or true if you need to use CSS Modules
        config: {
          namingPattern: "module".// The conversion mode is global/module
          generateScopedName: "[name]__[local]___[hash:base64:5]"}},// Add configuration here
      "postcss-px-scale": {
        enable: true.config: { scale: 0.5.units: "rem".includes: ["taro-ui"]}},},}};module.exports = function(merge) {
  if (process.env.NODE_ENV === "development") {
    return merge({}, config, require("./dev"));
  }
  return merge({}, config, require("./prod"));
};

Copy the code

Qr code scanning function

Scan code function is very simple, you can directly call the official method provided

Taro.scanCode({
    success: result= > {
      console.log("Callback for successful scan", result); }});Copy the code

See the official documentation for more usage, but I won’t introduce it here.

Debugging tips – Minidebug

Function is introduced

The main features include environment switching, identity Mock, application information acquisition, location simulation, cache management, scan, H5 jump, update version, etc.

The installation
yarn add @jdlfe/minidebug-next

Copy the code
Create a blank page debug

Use the CLI to quickly create a page

Taro create -- debug
Copy the code

Introducing component Debug

import { View } from '@tarojs/components'
import { Debug } from '@jdlfe/minidebug-next'

import './debug.scss'

const Bug: React.FC = () = > {

  return (
    <View>
      <Debug />
    </View>
  );
};

export default Bug;

Copy the code

Add a page configuration entry to open pages. Pages should be configured in subpackages otherwise the main package will be too large.

For more usage, see github.com/jdlfe/minid…

The source address

Github repository address

Finally, let’s introduce ourselves

Everybody is good, I am front side dish chicken of dish chicken each other peck, a front end development of some unknown small company moves brick member. This is my first post on the Nuggets, and I have to say that writing articles is exhausting, much more so than writing code, so I hope you can support me a lot. Later will continue to output some new articles.

You can also follow my public number: front-end development enthusiasts every day will collect some big guy articles and create some original articles, welcome to follow me.