Taro Development Diary-4 Cloud Function

Posted Jun 28, 20206 min read

Before has finished using local Storage to store information.
However, there is a problem with Storage. If the user deletes the applet, the previously stored information will no longer exist.

Using cloud functions

Create folder cloudfunctions\

Modify
project.config.json added

    "cloudfunctionRoot":"cloudfunctions/",

Right-click cloudfunctions=>New Node.js cloud function in the applet editor
image.png
Create the rouder function

Modify cloudfunctionsrouterpackage.json to add required plugins

{
  "name":"index",
  "version":"1.0.0",
  "description":"",
  "main":"index.js",
  "scripts":{
    "test":"echo \"Error:no test specified\" && exit 1"
  },
  "author":"",
  "license":"ISC",
  "dependencies":{
    "wx-server-sdk":"~2.1.2",
    "tcb-router":"^1.1.2"
  }
}

Modify cloudfunctionsrouterindex.js

//Cloud function entry file cloudfunctions\router\index.js
//WeChat sdk
const cloud = require('wx-server-sdk');
//The ancient project adds a route to the small program cloud function
const TcbRouter = require('tcb-router');
//Login method
const login = require('./controller/login');
//Method for saving user information
const saveUserInfo = require('./controller/saveUserInfo');
//log middleware
const log = require('./unit/log');
cloud.init();

//Cloud function entry function
exports.main = async(event, context) => {
  const app = new TcbRouter({ event });
  //app.use indicates that the middleware will apply to all routes
  app.use(log);
  //login routing
  app.router('login', login);
  //Save user information
  app.router('saveUserInfo', saveUserInfo);
  return app.serve();
};

New unit file

//cloudfunctions\router\unit\db.js
const cloud = require('wx-server-sdk');
cloud.init();
const db = cloud.database();

/**
 * Connect to the database if not created
 * @param {string} collect collection name(indicate)
 */
const connect = async collect => {
  return new Promise(async(resolve, reject) => {
    let _db;
    try {
      await db.createCollection(collect);
      _db = await db.collection(collect);
    } catch(error) {
      console.log(collect,'Already exists');
    }
    _db = await db.collection(collect).add({ data:{msg:'creat OK'} });
    resolve(_db);
  });
};

/**
 * adding data
 * @param {string} collect The name of the collection to be updated
 * @param {object} data
 */
const add = async({ collect, data }) => {
  try {
    await db.createCollection(collect);
  } catch(error) {
    console.log(collect,'Already exists');
  }
  data.createTime = db.serverDate();
  data.updataTime = db.serverDate();
  let res = await db.collection(collect).add({ data });
  return res;
};

/**
 * Find data
 * @param {string} collect The name of the collection to be updated
 * @param {object} filter filter condition
 */
const orderBy = async({
  collect,
  orderKey ='updataTime',
  order ='desc',
  field
}) => {
  try {
    await db.createCollection(collect);
  } catch(error) {
    console.log(collect,'Already exists');
  }
  let res = await db
    .collection(collect)
    .orderBy(orderKey, order)
    .field(field)
    .get();
  return res;
};
/**
 * Find data
 * @param {string} collect The name of the collection to be updated
 * @param {object} filter filter condition
 */
const find = async({ collect, filter, field }) => {
  try {
    await db.createCollection(collect);
  } catch(error) {
    console.log(collect,'Already exists');
  }
  let res = await db
    .collection(collect)
    .where(filter)
    .field(field)
    .get();
  return res;
};

/**
 * Update data, create if not
 * @param {string} collect The name of the collection to be updated
 * @param {object} filter filter condition
 * @param {object} data new data
 */
const update = async({ collect, filter, data }) => {
  try {
    await db.createCollection(collect);
  } catch(error) {
    console.log(collect,'Already exists');
  }
  data.updataTime = db.serverDate();
  let res = await db
    .collection(collect)
    .where(filter)
    .get();
  if(res.data.length) {
    res = await db
      .collection(collect)
      .where(filter)
      .update({
        data
      });
  } else {
    data.createTime = db.serverDate();
    res = await db.collection(collect).add({
      data
    });
  }
  return res;
};

module.exports = {
  connect,
  add,
  find,
  orderBy,
  update
};


//cloudfunctions\router\unit\log.js
const cloud = require('wx-server-sdk');
const log = async(ctx, next) => {
  ctx.data = {};
  ctx.body = {
    code:200
  };
  ctx.wxContext = cloud.getWXContext();
  //requested url
  const url = ctx._req.url;
  //Start processing time
  const start = new Date();
  console.log(`${start} =>[${url}]`);
  await next();
  //Knot speed processing time
  const endT = new Date();
  const ms = endT-start;
  //output log ctx.method request method ctx.url request address
  console.log(`${endT} <=[${url}][${ms}ms]\n`);
};

module.exports = log;

New controller

//cloudfunctions\router\controller\login.js
const {find} = require('../unit/db');

const login = async(ctx, next) => {
  let res = await find({
    collect:'userInfo',
    filter:{
      OPENID:ctx.wxContext.OPENID
    },
    field:{
      _id:false,
      country:true,
      province:true,
      city:true,
      gender:true,
      language:true,
      avatarUrl:true,
      nickName:true
    }
  });
  if(res.data[0]) {
    ctx.body.data = res.data[0];
  }
  await next(); //execute next middleware
};
module.exports = login;


//cloudfunctions\router\controller\login.js
const {update} = require('../unit/db');

const saveUserInfo = async(ctx, next) => {
  let userInfo = Object.assign({}, ctx.wxContext, ctx._req.event.data);
  let res = await update({
    collect:'userInfo',
    data:userInfo,
    filter:{
      OPENID:ctx.wxContext.OPENID
    }
  });
  ctx.body.data = res;
  await next(); //execute next middleware
};
module.exports = saveUserInfo;

After editing
Upload cloud function
image.png
You can perform the next test to verify that the cloud function is no problem~

Then the cloud function is added

Call the cloud function on the applet

First add in app.tsx

//Initialize the cloud function
Taro.cloud.init();

Modify srcstoreuserInfo.ts

//src\store\userInfo.ts
//Introduce observable;
import {observable} from'mobx';
import {getStorageSync, cloud} from'@tarojs/taro';

const userInfoStore = observable({
  //Objects storing basic user information
  userInfo:{},
  //Method of writing information
  saveInfo(userInfo:userinfo) {
    if(this!.userInfo) {
      this.userInfo = Object.assign({}, this.userInfo, userInfo);
      cloud.callFunction({
        name:'router',
        data:{
          $url:'saveUserInfo',
          data:this.userInfo
        }
      });
    }
  },
  //Read user information from local
  readInfo() {
    const userInfo = getStorageSync('userInfo');
    this.userInfo = Object.assign({}, this.userInfo, userInfo);
  },
  getCloudInfo() {
    cloud
      .callFunction({
        name:'router',
        data:{
          $url:'login'
        }
      })
      .then((res:any) => {
        console.log({ res });
        this.userInfo = res.result.data || {};
      });
  }
});
export default userInfoStore;

Then modify src\pages\index\index.tsx

import {ComponentType} from'react';
import Taro, {Component, Config} from'@tarojs/taro';
import {View, Button} from'@tarojs/components';
import {AtAvatar} from'taro-ui';

//Introduce mobx decorator
import {observer, inject} from'@tarojs/mobx';
import'./index.scss';

//Edit the props interface type under src\pages\index\index.tsx
type PageStateProps = {
  //Add userInfoStore
  userInfoStore:{
    userInfo:userinfo;
    saveInfo:Function;
    getCloudInfo:Function;
  };
};

interface Index {
  props:PageStateProps;
}

//Inject userInfoStore
@inject('userInfoStore')
@observer
class Index extends Component {
  config:Config = {
    navigationBarTitleText:'Home'
  };

  /**
   * @description:Get user information
   * Basic user information returned by @param {Object} detail onGetUserInfo
   * @return null
   */
  getUserInfo({ detail }) {
    const {userInfoStore} = this.props;
    userInfoStore.saveInfo(detail.userInfo);
  }

  //Add didshow hook to execute every time the page is displayed
  componentDidShow() {
    const {userInfoStore} = this.props;
    //Read user information when the page is displayed
    userInfoStore.getCloudInfo();
  }
  render() {
    const {userInfo} = this.props.userInfoStore;
    return(
      <View className='index'>
        {/* buttonUse getUserInfo to get basic user information in a small program */}
        <Button
          openType='getUserInfo'
          onGetUserInfo={this.getUserInfo.bind(this)}
          className='index-avatarUrl-btn nobtn-style'
        >
          <View className='avatar-box'>
            <AtAvatar
              image={userInfo.avatarUrl}
              size='large'
              circle
              text={userInfo.avatarUrl?'':'Empty'}
            ></AtAvatar>
          </View>

          <View className='nickName-box'>
            {userInfo.nickName ||'Click to login'}
          </View>
        </Button>
      </View>
   );
  }
}

export default Index as ComponentType;

In this way, after clicking the user authorization picture, the obtained information will be stored in the userInfo library.
Every time it starts, it will read the current user's information from userInfo

gitaddress