New instance of the tour created on every render of the provider (Relates to #282 ?)
Closed this issue · 4 comments
Every time a component, that uses the tour context, is re-rendered a new instance of the tour is created.
The new instance is then provided to child components via the context.
If you're trying to trigger the tour automatically using an effect, this will result in the tour being re-created (the tour id will change) every time the provider component is re-rendered.
We are accessing the tour in several components to read the isActive() flag. Maybe this is wrong?
import { useContext } from 'react'
import { ShepherdTourContext } from 'react-shepherd'
const tour = useContext(ShepherdTourContext)
AppRouter.js - Mounting point
import { Router, Route, Switch } from 'react-router-dom'
import { steps } from '../components/tour/steps';
...
const AppRouter = ({ isTourCompleted, ...rest }) => {
//shepherd tour
const tourOptions = {
defaultStepOptions: {
classes: 'shepherd-theme-introTour',
cancelIcon: { enabled: true }
},
useModalOverlay: true
};
return (
<React.Fragment>
<Router history={history}>
<ShepherdTour steps={steps} tourOptions={tourOptions}>
{(!isTourCompleted) &&
<StartTour autoStart={!isTourCompleted}/>
}
<Suspense fallback={<LoadingSpinnerFullPage />}>
<div className="appContainer">
<Route path="" render={() => <Sidebar />} />
...
</ShepherdTour>
</Router>
</React.Fragment>
)
}
const mapStateToProps = (state) => ({
isTourCompleted:state.userSettings.isTourCompleted
})
export default connect(mapStateToProps)(AppRouter)
StartTour.js Component - Auto starts the tour
import { useEffect, useContext } from 'react'
import { ShepherdTourContext } from 'react-shepherd'
export const StartTour = (props) => {
console.log('Shep StartTour props', props)
const tour = useContext(ShepherdTourContext);
useEffect(() => {
if(props.autoStart &! tour.isActive()){
setTimeout(()=>{
tour.start()
console.log('Shep tour', tour.id, tour.isActive())
}, 5000)
}
}, [props.autoStart])
return null
}
Sidebar.js Component - Has a onClick() to start the tour
export const Sidebar = (props) => {
const tour = useContext(ShepherdTourContext);
console.log('Shep sidebar tour', tour.id)
return (
<React.Fragment>
...
<p className="tourLinkContainer" onClick={tour.start}>
<img className="tourLinkContainer__img" src='/images/busStop.svg' />
<span className="tourLinkContainer__text">{isNavOpen ? "Guide" : ""}</span>
</p>
</React.Fragment>
);
}
The console output when updating the 'isTourCompleted' flag in the store will be:
***INITIAL RENDER***
Shep sidebar tour tour--34d97abe-ea40-43a2-965e-3fd201f272cd
Shep sidebar tour tour--c1f5a161-9fa3-43e4-a109-bcbb0d8a27a2
Shep sidebar tour tour--c1f5a161-9fa3-43e4-a109-bcbb0d8a27a2
Shep sidebar tour tour--c1f5a161-9fa3-43e4-a109-bcbb0d8a27a2
***SET 'isTourCompleted' FLAG IN STORE***
Shep StartTour props Object { autoStart: true }
Shep StartTour props Object { autoStart: true }
Shep sidebar tour tour--83666ead-d23b-4751-9159-1ef3c1ea0864
Shep sidebar tour tour--83666ead-d23b-4751-9159-1ef3c1ea0864
Shep sidebar tour tour--8a4dce0a-3f9f-40e3-91dc-e23065961e99
Shep sidebar tour tour--8a4dce0a-3f9f-40e3-91dc-e23065961e99
Shep StartTour tour tour--83666ead-d23b-4751-9159-1ef3c1ea0864 true
The StartTour component should not use the old instance of the tour.
(the id should be 'tour--8a4dce0a-3f9f-40e3-91dc-e23065961e99')
When clicking the < p > in Sidebar.js the correct id is used (tour--8a4dce0a-3f9f-40e3-91dc-e23065961e99).
How can this behaviour be prevented?
@YM-KA perhaps setting up a codesandbox would make it easier to debug together? Offhand, I'd think it was correct anytime the component rerenders that you'd get a new tour, so you'd either prevent that via state in your app or perhaps only having the tour on a certain route, etc. Shepherd doesn't have any mechanism for to prevent multiple tours, that all falls on the app itself.
I am having the same issue as well using NextJS, it will become a new instance when I change the page, any solutions so far?
I am having the same issue as well using NextJS, it will become a new instance when I change the page, any solutions so far?
In the end, I just use the JS version instead and handle the instance myself
@busyxiang could you provide an example with this behavior? Seems like it's been fixed since, #283.
Otherwise, care to share how you proceeded and see if there's anything we could change/improve?