Wrap Shepherd.js around a React application
Baspa opened this issue ยท 7 comments
I want to implement the Shepherd.js package in my React application to make a guided tour. They have a React wrapper which I thought would be good to use. My application consist about a huge amount of components so I want to wrap the tour around my application so it can be used everywhere and across multiple pages. In my application I already have some Higher-Order Components like dialogs which are wrapped around my App
:
class Root extends Component {
render() {
return (
<MuiThemeProvider theme={theme}>
<MuiPickersUtilsProvider utils={MomentUtils}>
<I18nProvider>
<LoadingProvider>
<DeleteDialogProvider>
<WarningDialogProvider>
<StateProvider>
<Router>
<App />
</Router>
</StateProvider>
</WarningDialogProvider>
</DeleteDialogProvider>
</LoadingProvider>
</I18nProvider>
</MuiPickersUtilsProvider>
</MuiThemeProvider>
);
}
}
At first I thought I could just wrap the ShepherdTour
and TourMethods
components around App
it but then I got this error:
Warning: A context consumer was rendered with multiple children, or a
child that isn't a function. A context consumer expects a single child
that is a function. If you did pass a function, make sure there is no
trailing or leading whitespace around it.
Their example on their GitHub page looks like this:
<ShepherdTour steps={steps} tourOptions={tourOptions}>
<TourMethods>
{(tourContext) => (
<button className="button dark" onClick={tourContext.start}>
Start Tour
</button>
)}
</TourMethods>
</ShepherdTour>
Is it possible to make this a HOC so I can call the tourContext.start
function from everywhere in my application? I am a bit stuck on how I can do this because I am not sure how to implement this well. Any ideas are welcome.
@chuckcarpenter this sounds like a logical request. Any idea what we need to do to support it?
@Baspa I need to update the readme as well, since I made a few changes to use hooks in the component, so I recommend setting it up more like what I have here: https://github.com/shipshapecode/react-shepherd/blob/master/example/src/App.js
It's a cleaner way to handle context, from what I understand of it. Let me know how that works for you.
@Baspa I need to update the readme as well, since I made a few changes to use hooks in the component, so I recommend setting it up more like what I have here: https://github.com/shipshapecode/react-shepherd/blob/master/example/src/App.js
It's a cleaner way to handle context, from what I understand of it. Let me know how that works for you.
This definitely works for me now.
Any idea on how I can check in the beforeShowPromise
function if a compononentDidMount
? Because sometimes I get the error that the element don't exist yet because the component didn't mount fast enough @chuckcarpenter
@Baspa beforeShowPromise
wouldn't know much about lifecycle methods. I haven't had to do this in React, but you can use the native MutationObserver
and then call the next step once the node exists in the DOM.
Okay thank you, I am gonna take a look at it @chuckcarpenter
I ended up with creating a function that checks if the element exist, if it doesn't it should check again after 0,5 seconds.
function waitForElementToDisplay(selector) {
return new Promise(function (resolve) {
(function checkIfElementExists() {
if (document.querySelector(selector) !== null) {
resolve();
} else {
setTimeout(checkIfElementExists, 500);
}
})();
})
}
Then in the beforeShowPromise
function I made the Promise function
async so that it waits until the function is resolved:
beforeShowPromise: () => waitForElementToDisplay('.meetingTitle'),