preface


Recently, I have been using Taro to develop a small program, and I have encountered many problems. The first problem I encountered was the problem of transferring data between pages. Please record the solution process and the final solution for your reference.

Plan 1 (Taro. EventCenter) ❌


The first thing that comes to mind when communicating across pages is the way messages are sent. Thanks to Taro, they provide a global message center: Taro. EventCenter. Usage:

Taro.eventCenter.on('eventName',handler) // Listen for an event and accept arguments
Taro.eventCenter.trigger('eventName') // Trigger an event and pass the parameter
Taro.eventCenter.off('eventName',handler) // Cancel listening on an event to a handler
Copy the code

Start practicing

A The page triggers an event

await navigateTo({url: 'page B'}
Taro.eventCenter.trigger('eventName',data)
Copy the code

B Page listening events

useEffect(() = > {
  Taro.eventCenter.on('eventName'.(data) = > {
    // do something}}), [])Copy the code

The ideal is full, the reality is very skinny, this is not effective, because after page A event triggered, page B is not listening. Don’t worry, how about I add a setTimeout and wait?

await navigateTo({url: 'page B'}
setTimeout(() = > {
 Taro.eventCenter.trigger('eventName',data)
},200)
Copy the code

Testing is ok! But that’s certainly not what we want. Plan one has been abandoned at this point.

Thinking 🤔


And then we can think about, can we consume data while we’re listening? In this case, two requirements need to be met:

  • A Data is stored before the page is redirected

  • B page subscription time to consume data

Thinking of this, the BehaviorSubject of RxJS gradually surfaced

For those of you who are not familiar with this, check out the BehaviorSubject

Scheme 2 (RxJS BehaviorSubject) ✅


Let’s take a look at two objects:

  • Observable, data producer, the party that produces data.

  • An Observer is a person who receives data.

BehaviorSubject:

Being both producer and consumer, it has a concept of “current value”. It stores the latest value sent to the consumer. When a new observer subscrires, the BehaviorSubject immediately receives the “current value” from the BehaviorSubject. You need an initial value when defining a BehaviorSubject.

Usage:

import { BehaviorSubject } from 'rxjs';
const subject = new BehaviorSubject(0); // Create an initial value of type number
subject.subscribe({
  next: (v) = > console.log(`observerA: ${v}`) // Consumption data
});

subject.next(1);// Production data
subject.next(2);// Production data

subject.subscribe({
  next: (v) = > console.log(`observerB: ${v}`) // Consumption data
});

subject.next(3);

// Print the result
// observerA: 0 A subscription the current value is 0, the initial value
// observerA: 1
// observerA: 2
// observerB: 2 B subscription the current value is 2
// observerA: 3
// observerB: 3
Copy the code

Keep practicing!

Implement two hooks that make it easy to create and subscribe to BehaviorSubject

  • UseBehaviorSubject Indicates the performance of the object
import { BehaviorSubject } from 'rxjs'
import { useConst } from 'whooks'

function useBehaviorSubject<T> (init: T) {
  const behaviorSubject = useConst(new BehaviorSubject<T>(init))
  useEffect(() = > {
    return () = > {
      behaviorSubject.unsubscribe()
    }
  }, [behaviorSubject])
  return behaviorSubject
}

export default useBehaviorSubject

Copy the code

There is useConst, and useConstCallback, which is the hooks I use, which include ref.

  • UseBehaviorSubscription is used for consumption
import type { BehaviorSubject } from 'rxjs'
function useBehaviorSubscription<T> (subject: BehaviorSubject<T>, next: (value: T) => void) {
  useEffect(() = > {
    const subscription = subject.subscribe(next)
    return () = > {
      subscription.unsubscribe()
    }
  }, [subject, next])
}
export default useBehaviorSubscription
Copy the code

Create a global countBehaviorSubject

For ease of administration, we create a GlobalProvider and put countBehaviorSubject into the Context

const useGlobalProviderFacade = () = > {
  const countBehaviorSubject = useBehaviorSubject(0)
  return {
    countBehaviorSubject
  }
}
export type GlobalContextType = ReturnType<typeof useGlobalProviderFacade>
export const GlobalContext = React.createContext<GlobalContextType>({} as GlobalContextType)
export const GlobalProvider: React.FC = ({ children }) = > {
  const globalData = useGlobalProviderFacade()
  return <GlobalContext.Provider value={globalData}>{children}</GlobalContext.Provider>
}

export const useGlobal = useContext(GlobalContext)

Copy the code

Look at the effect 💥

A page to publish data

const { countBehaviorSubject } = useGlobal()

const onCreated = async () => {
  countBehaviorSubject.next(1)
  await Taro.navigateTo({url: 'page B'})}Copy the code

B Page consumption data

const { countBehaviorSubject } = useGlobal()
const next = useConstCallBack((value) = > {
  // do something
})
useBehaviorSubscription(countBehaviorSubject, next)
Copy the code

Using the result, yes, at this point, a simple call to a few lines of code in the page can achieve cross-page communication.

const subject = useBehaviorSubject(init:T) / / create
subject.next(data:T) / / release
useBehaviorSubscription(subject,handle:(value:T) = > void) / / subscribe
Copy the code

conclusion


  • The excellent performance of RxJS BehaviorSubject solves the page communication problem.
  • The root of the problem is to store the production data before jumping to the page and then consume it when subscribing to the page after jumping.
  • This is also used later in the process of customizing tabBar with permissions, which is relatively convenient for individuals.

The last


  • It is the first time to do a small program project, and I have little experience. Considering the development efficiency, I will directly use Taro.
  • In the process of solving the problem, we may also take a detour, we can also provide a good solution.
  • Finally, I hope to provide some ideas for students who have encountered the same problem with Taro for the first time.