Closed mtr1990 closed 8 months ago
Hey @mtr1990
Setting the callback data in a state is an anti-pattern since the callback receives all the lifecycle events before the beacon or tooltip is rendered, which probably creates a race condition and breaks the functionality. The callback changes significantly, and saving its data in a state will force the component to re-render like crazy.
Adding a "next tick" setTimeout to the state setter inside the callback handler proves that it is, in fact, a race condition.
setTimeout(() => {
setCallbackData(data);
}, 0);
// This "works", but it's a huge red flag.
If you need to access the data outside the callback, I'd recommend saving it to a mutable ref instead.
function App() {
const joyrideState = useRef<CallBackProps | undefined>();
const handleJoyrideCallback = (data: CallBackProps) => {
joyrideState.current = data;
}
...
console.log('joyrideState', joyrideState.current);
}
Hi @gilbarbara ,
Thank you for your response.I tried your way but the status always returns undefined
for joyrideState.current
and helpers.current
https://codesandbox.io/p/sandbox/frosty-wozniak-w7sltw?file=%2Fapp%2Fpage.tsx%3A62%2C15
Hey @mtr1990
The initial logs will be undefined because the refs weren't set yet. And changing a ref
doesn't re-render the component.
The Joyride component won't re-render the parent when it changes its internal state.
The example is too simple. Try adding this to see the logs:
useEffect(() => {
setTimeout(() => {
console.log("joyrideState", joyrideState.current);
console.log("helpers", helpers.current);
}, 1000);
}, []);
What are you trying to achieve? Have you tried it in your real-life project?
If you try to use the helpers
or the joyrideState
in other methods, they will be available in the ref...
Anyway, this is not a problem with the library itself, just the implementation. So, good luck!
Hi @gilbarbara
I am using in my real project. My desired goal is to access properties outside the callback.
But so far I have not achieved this despite trying many ways
Example: https://docs.react-joyride.com/callback
{
action: 'start',
controlled: true,
index: 0,
lifecycle: 'init',
size: 4,
status: 'running',
step: { the.current.step },
type: 'tour:start',
}
When I access inside the callback everything works fine in vite.js
. But on next.js
it doesn't work as expected
const [run, setRun] = useState(true);
const [callbackData, setCallbackData] = useState();
const handleJoyrideCallback = (data: CallBackProps) => {
const { status } = data;
const finishedStatuses: string[] = [STATUS.FINISHED, STATUS.SKIPPED];
if (finishedStatuses.includes(status)) {
setRun(false);
}
setCallbackData(data); // => vite.js version works fine but next.js doesn't
};
I also updated the example using outside callback with refs but returns undefined.
Can you help based on codesanbox? https://codesandbox.io/p/sandbox/frosty-wozniak-w7sltw?file=%2Fapp%2Fpage.tsx%3A50%2C23
You can't set the callback data in a state. That is an anti-pattern that forces the parent component to re-render dozens of times without needing and creates a race condition that breaks the internal state of the Joyride component... The vite version isn't working fine, it's just hiding the problem, and next.js isn't so forgiving.
Can't you call a method inside the callback when the state matches your condition? Why do you need the joyride state outside the callback? Did you check the other examples in the demo? The Controlled one has quite complex logic inside the callback.
🐛 Bug Report
Displayed in wrong position in
next.js
On my localhost the
vite.js
version does not have this errorTo Reproduce
1.Result after deleting
setCallbackData(data)
:2.Result with
setCallbackData(data)
:Expected behavior
Displayed in the correct position with
setCallbackData(data)
Link to repl or repo (highly encouraged)
https://codesandbox.io/p/sandbox/frosty-wozniak-w7sltw?file=%2Fapp%2Fpage.tsx%3A53%2C27