-
-
Notifications
You must be signed in to change notification settings - Fork 214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can this be used on multiple screens? #17
Comments
Hi, Can anyone share code on how to achieve this multiscreen tour. In my case I have two bottom tabs(A and B), the tour goes from one tab(A) to next tab(B). My tour sequence is like A->B->A.
|
Here's something you can try.
const App = () => (
<TourGuideProvider>
<AppContents />
</TourGuideProvider>
)
// AppContents.js
...
const {
canStart,
start,
eventEmitter,
} = useTourGuideController()
useEffect(() => {
if (canStart) {
start()
}
}, [canStart])
...
Note: If you are using Redux navigation on top of a Stack Navigator, the Navigation service does not work without some modifications. // This is my package.json, no need to have these exact versions, but just including it for clarity.
{
"react-navigation": "^4.4.0",
"react-navigation-redux-helpers": "^2.0.6",
"react-navigation-stack": "^1.10.3",
"react-redux": "^6.0.0",
"redux": "^4.0.1",
"redux-persist": "^5.4.0",
"redux-persist-seamless-immutable": "^2.0.0",
"redux-saga": "^1.0.0",
"reduxsauce": "^1.1.0",
"rn-tourguide": "^2.7.1",
} You might have to do something like below. ...
function navigate(routeName, params) {
_container.props.dispatch(
NavigationActions.navigate({
type: 'Navigation/NAVIGATE',
routeName,
params,
}),
)
}
function getCurrentRoute() { // returns the name of the current screen (defined in your stack navigator)
if (!_container || !_container.props.state) {
return null
}
const { routes, index } = _container.props.state
return routes[index].routeName || null
}
...
// tour.js
const tour = {
screenNameA: 'screenNameB',
screenNameB: 'screenNameC',
...
}
export default tour
A major plus is that we do not have to refactor our class-based components into functional components, and we do not have to insert useEffect hooks into every screen. Make sure that your TourGuideZones are indexed from 1 on each screen, since it will be seen as a new tour by this package. // AppContents.js
import NavigatorService from './services/navigator' // The path to that file will of course vary
import tour from './services/tour'
...
useEffect(() => {
if (canStart) {
start()
}
}, [canStart, NavigatorService.getCurrentRoute()]) // we change this
useEffect(() => { // we add this hook
eventEmitter.on('stop', () => { // When the tour for that screen ends, navigate to the next screen if it exists.
const nextScreen = tour[NavigatorService.getCurrentRoute()]
if (nextScreen) {
NavigatorService.navigate(nextScreen)
}
})
return () => eventEmitter.off('*', null)
}, [])
...
|
@patrickspafford Shouldn't simply adding another TourGuideZone on the other screen work? |
@ThallyssonKlein Probably not in the way that you'd find useful, but you are correct that the provider is made available to all its children. To my knowledge, there's nothing in this library that would automatically trigger a segue to the next screen, which was part of the idea here. This method automatically transitions to the next page when the tour for that screen ends and gives you the option to hook into different points of the tour to trigger events that you might dispatch to the Redux store. It doesn't require you to add the tour hooks to every screen that's part of the tour (That would be annoying). All you have to do is add the TourGuideZones in the render/return methods once you get it set up in the root component (shown in my other comment). Let me give you an example of dispatching actions at different points in the tour, since I haven't shown that. // tour.js
...
screenNameA: {
nextScreen: 'screenNameB',
actionOnLoad: () => storeData(`@screenNameA`), // save to local storage that this screen has been toured
actions: {
1: () => { // at step 1 of the tour on screenNameA, dispatch these actions
store.dispatch(action1a)
store.dispatch(action1b)
},
2: () => {
store.dispatch(action2a)
store.dispatch(action2b)
}
}
... The useEffect hooks in the root container need to be modified to make use of the extra parts above, though. Does that make sense? |
I cannot implement Redux in my project. Is there a way to do this using context API? |
The problem here is that this library does not recognize the step on the other screen as a total part of the tutorial. I created a context with purpose to start the tutorial again on the other screen
My App.js
I confess that I am having trouble understanding your solution using Redux, and whenever I tried to implement this project I had difficulties. It is too simple a project for Redux. It's like killing a cockroach with a cannon shot. I want to quickly develop this tutorial. Edited I tested the code again, and noticed that on the screen where the third step is present, the behavior has something that I didn't pay attention to. Yes, the steps of the previous screen appear, but on this new screen the tutorial has 3 steps and the last one appears, but the behavior I need is to ignore the steps on the other screen. |
Just started working on the same thing, I think you can pass a step number to start and it will start there |
Using context, no redux
When the user clicks on the Tab Icon, the tutorial continues. The "previous" button is broken though. It needs to navigate back to the previous tab, right now it just goes back to step 5. Will probably write a custom tooltip component, hopefully one that can take props from the TourGuideZone, so it can be generic. |
It worked perfectly, thanks. |
I'm almost done with the tutorial on my APP. But this last step complicated things. I will describe the scenario to see if you can think of a solution. The component below is a component that is present on the second screen. This is where the steps on the second screen appear. And there is a button that when clicked, changes the context. This change consists of hiding itself and creating 2 new components on the screen.
The Alone Component:
This component is already present on this second screen 2 times. At the beginning the second screen consists of 1 element of the Compared component and 2 of the Alone component. However, with the event in the Compared component, it adds two more elements alone. I need to have a step on the button for the component Alone and another one on the one below (The ones that start on the screen, not the ones that are added), but these steps need to appear only after the event in the Compared component. I made a logic where I can know which component is which by keyI. In my opinion it had everything to work, but I'm getting this exception: Update Taking the uses of canStart out of my context, the error started to appear in the function that unregisters the steps. |
I found a temporary solution: On the second screen there are 2 steps that need to appear and two more that should only appear after some actions. Remounting the screen results in the error I showed in the message above. What I did now was: The steps that should not appear in the sequence I put with negative keys or 0, like -2, -1, 0. And start is called on this second screen in the items ahead that need to appear, such as start(3), and 3 leads to four, which is the last recorded step. I created a fork with a custom Tooltip for my App as a temporary solution. |
Hello,
I have a React Navigation in place and I'm using this library to show a tour for the first tab.
Is there a way to use this, when switching the tab, or go into a new Screen, to start another tour in that specific screen?
The text was updated successfully, but these errors were encountered: