preface

In applets, there is a globally unique store of globalData, but each page does not know if globalData has changed and updates the page’s data. For example, page A has changed globalData, but page B does not know that globalData has changed. Page B can only retrieve globalData during the onShow life cycle and setData

Even on the same page, I changed globalData without the page knowing it and had to manually go setData so that the data in the page would be re-rendered

Of course, this is just an idea, and I’m not considering multiple setData degradation. If you’re reading this blog, you can think of it as learning observer mode. Haha, of course, it would be nice if you liked it

Second, fix the bug. The js file for each Page of the applet is a Page(object), and reflects and Proxy are used to Proxy (object) so that only the routing stack setData on the current Page, and reduce coupling

What is the observer model?

Thanks for correcting the words in the comments section

Observer mode, with two roles, one is the target, one is the observer. Can be figuratively compared to teachers and students

The teacher is lecturing on stage (Posting news, triggering events), the students are listening to the teacher (receiving news) and then absorbing knowledge (performing tasks). If the teacher thinks you are being distracted, he will ask you to leave the classroom (deleting observers).

The teacher thinks you are introspective enough, he will let you into the classroom (add observers)

class Teacher{
  constructor() {this.students=[];// To store students, i.e. to store observers
  }
  add(student){
		this.students.push(studnet)
  }
  remove(student){
    this.students.forEach((item,index) = >{
      if(item==studnet){
        this.students.splice(index,1)
        return;
      }
    })
  }
  say(){// The teacher lectured
    this.students.forEach(item= >{
      item.listen()// The students are required to attend the class}}})class Student{
  listen(){
    console.log("I'm listening.")}}Copy the code

Conclusion:

The target has three abilities:

  1. Add observer
  2. Delete observer
  3. Notifies the observer to perform a task

The observer has the ability to:

  1. Perform a task

Use observer mode in applets

The applets directory is as follows

The publisher. In js

class Publisher {/ / publisher
  constructor() {
    this.observers = [];// Store the observer
  }
  add(observer) {// Add an observer
    this.observers.push(observer);
  }
  remove(observer) {// Delete the observer
    this.observers.forEach((item, index) = > {
      if (item == observer) {
        this.observers.splice(index, 1);
        return; }}); } notify() {// Publish a message to the observer
    this.observers.forEach(item= > {
      item.update();// Create an update function on each page to update globalData and render it}); }}// This class inherits Publisher and listens for globalData changes
class GlobalDataPublisher extends Publisher {
  constructor(globalData) {
    super(a);this.globalData = globalData;
    this.observers = [];
  }
  getGlobalData() {
    return this.globalData;
  }
  setGlobalData(globalData) {// globalData notifies observers of any changes
    this.globalData = globalData;
    this.notify(); }}module.exports = {
  Publisher,
  GlobalDataPublisher
};

Copy the code

app.js

//app.js
var { GlobalDataPublisher } = require('./utils/publisher');
App({
  onLaunch: function() {
    // Mount this class to the globally unique instance of App
    this.globalDataPublisher = new GlobalDataPublisher(this.globalData);
  },
  globalData: {
    userInfo: {
      name: 'Hu Zhiwu'.age: 18.job: 'Front Siege Lion'}}});Copy the code

Create four new pages

WXML <view> <text>name:{{userinfo.name}}</text> <text>age:{{userinfo.age}}</text> <text>job:{{userinfo.job}}</text> </view> <view bindtap="changeName"> </view> <view Bindtap ="changeJob"> </view>Copy the code
// js
// This is what each page needs to do, fetching globalData and setData to render the page in time
update() {
  	console.log("User page update")
    const app = getApp();
    const globalData = app.globalDataPublisher.getGlobalData();
    this.globalData = globalData;
    this.setData({ ... globalData }); },Copy the code
//j s
// each page onLoad. I need to add observers,
onLoad: function(options) {
    const app = getApp();
    app.globalDataPublisher.add(this);// Add an observer
    this.globalDataPublisher = app.globalDataPublisher;
    this.globalData = app.globalDataPublisher.getGlobalData();
    this.setData({ ... this.globalData }); },Copy the code
// js business function
// It is used to check whether the update is global in real time
changeName() {
  	console.log("User page updated, changeName")
    this.globalData.userInfo.name = 'Front end pupil';
    this.globalDataPublisher.setGlobalData(this.globalData);
  },
  changeJob() {
    console.log("User page update, changeJob")
    this.globalData.userInfo.job = 'Front end handyman';
    this.globalDataPublisher.setGlobalData(this.globalData);
  },
Copy the code

Click on the four tabBar pages to register the observer, then click on the change name, and you’ll see that other pages have also updated globalData and setData

Second, use Reflect and Proxy to Proxy page

If every page needs to add the code to register the observer, and the update function is too much trouble.

We can see that each Page of the applet is a Page, and we can proxy and reflect, add the code that we need,

function createProxyPage(objProps){
  Reflect.set(objProps,"update".function(){... Code as above})return objProps
}
Page(createProxyPage{
     data:{}
		...
})
Copy the code

This makes it easy to add update functions to each page using createProxyPage

So how do I add code from the onLoad lifecycle that doesn’t override the original onLoad

function createProxyPage(objProxy) {
  Reflect.set(...)
  const proxyPage = new Proxy(objProxy, {
    get(target, prop) {
      if (prop === 'onLoad') {
        // Proxy the onLoad function
        Reflect.set(
          target,
          prop,
          new Proxy(target[prop], {
            // Once onLoad is executed, the following proxy is called
            apply(target, thisArgument, argumentsList) {
              ThisArgument is the page object that calls the onLoad function
              constapp = getApp(); app.globalDataPublisher.add(thisArgument); thisArgument.globalDataPublisher = app.globalDataPublisher; thisArgument.globalData = app.globalDataPublisher.getGlobalData(); thisArgument.setData({ ... thisArgument.globalData });// After executing the register observer code, execute the original onLoad code for each page
              // That is, the onLoad function will not overwrite every page, and the onLoad function will execute as usual
              return Reflect.apply(target, thisArgument, argumentsList); }})); }}}); }Copy the code

The complete code is as follows

function createProxyPage(objProps) {
  Reflect.set(objProps, 'update'.function() {
    console.log('update data ');
    const pages = getCurrentPages();
    const page = pages[pages.length - 1];
    if (this === page) {
      const app = getApp();
      const globalData = app.globalDataPublisher.getGlobalData();
      this.globalData = globalData;
      this.setData({
        ...globalData
      });
    }
  });
  const proxyPage = new Proxy(
    objProps,

    {
      get(target, prop) {
        if (prop === 'onShow') {
          Reflect.set(
            target,
            prop,
            new Proxy(target[prop], {
              apply(target, thisArgument, argumentsList) {
                constapp = getApp(); thisArgument.globalData = app.globalDataPublisher.getGlobalData(); thisArgument.setData({ ... thisArgument.globalData });console.log('onShow update data ');
                return Reflect.apply(target, thisArgument, argumentsList); }}));if (prop === 'onLoad') {
            Reflect.set(
              target,
              prop,
              new Proxy(target[prop], {
                apply(target, thisArgument, argumentsList) {
                  constapp = getApp(); app.globalDataPublisher.add(thisArgument); thisArgument.globalDataPublisher = app.globalDataPublisher; thisArgument.globalData = app.globalDataPublisher.getGlobalData(); thisArgument.setData({ ... thisArgument.globalData });return Reflect.apply(target, thisArgument, argumentsList); }})); }}return Reflect.get(target, prop); }});return proxyPage;
}
module.exports.createProxyPage = createProxyPage;

Copy the code

The code is in the link below:

Github.com/huzhiwu1/gl…

conclusion

Author: Hu Zhiwu

If there are any mistakes or omissions, please correct them. Give it a thumbs up, people