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.