axe-core-npm
axe-core-npm copied to clipboard
react: add delay to run
Currently there is no option for delaying the start of axe.run
so there are problems when APIs or routes are changed but the DOM hasn't updated yet. Axe runs during an incomplete DOM step and so returns errors that aren't really errors as the DOM is still loading.
See https://github.com/dequelabs/react-axe/issues/74, https://github.com/dequelabs/react-axe/issues/134, https://github.com/dequelabs/react-axe/issues/182, https://github.com/dequelabs/react-axe/issues/183, https://github.com/dequelabs/react-axe/issues/122
thanks for moving the issue over @straker, much appreciated.
Thank you, commenting to follow.
Reporting an error thrown when using axe with a timer. Package used: "@axe-core/react": "4.0.0"
export default function useAxe(): void {
if (!environment.isProduction) {
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-extraneous-dependencies
const axe = require("@axe-core/react");
// axe(React, ReactDOM, 1000) // FIXME https://github.com/dequelabs/react-axe/issues/183
const timer = setInterval(() => {
axe(React, ReactDOM);
}, 1500);
// clearing interval
return () => clearInterval(timer);
});
}
}
When my top App component reloads during the user sign in process, I get this error
index.js:184 Uncaught (in promise) Axe is already running. Use
await axe.run()
to wait for the previous run to finish before starting a new run.
I tried to give setInterval an async function, or run an iife in useEffect with an async function, and await axe()
, to not avail. Moreover, axe.run is not a function
.
Hi 👋
Since my project uses React Router, we can't use axe-core-npm 😞 (because of https://github.com/dequelabs/react-axe/issues/122). But it seems so useful 🤩 Any news about the progress of this fix?
Thank you so much for this tool 🙏
It's pretty crucial to support (react route) rerendering. Any workarounds?
Also it doesn't seem to pick up any rerenders, reduced use case here: https://codesandbox.io/s/axe-corereact-not-picking-up-on-rerenders-cib66
Hi there 😄
Any news regarding this issue?
Thanks a lot 🙏
I too am interested in this issue. We were previously using react-axe, which works with react-router, but after upgrading to axe-core-npm, the tool no longer works when switching routes. This is critical, so for now, we will need to use the deprecated package.
Hi, great package. But actually with React Router v6, lazy routes and React 18 it's not triggering on page navigation and also not on initial load. For example, it gives an error of no h1
element, but the actual element exists inside a react router page and axe is not recognising it.
hello guys, I'm waiting for some update of this topic. :package:
Just added @axe-core/react
and facing the same problems with react-router 6.
Initially it will throw a missing h1
and upon hard refresh in the browser, it seems like it's working normally, but it does not trigger on rerenders, HMR nor on route changes.
We use React 18 and React-Router 6
@michael-siek what's the status of it? This issue is >2 years old. Any ideas what can be the issue? How we can help you guys?
@karpiuMG We're currently investigating getting our package to work with React 18, so we don't have a timeline for when this will get done.
I solved it this way:
import React, { useEffect, useRef, useState } from 'react'
import ReactDOM from 'react-dom'
const runAxe = () => {
let axeRunning = false
return () => {
if (!axeRunning) {
axeRunning = true
import('@axe-core/react').then(axe =>
axe.default(React, ReactDOM, 0).then(() => {
axeRunning = false
})
)
}
}
}
const Axe = () => {
const [mutationCount, setMutationCount] = useState(0) // State variable to track DOM mutations
const axeRunner = useRef(runAxe())
useEffect(() => {
// Create a MutationObserver and observe the entire document for DOM mutations
const observer = new MutationObserver(() => {
setMutationCount(count => count + 1)
})
observer.observe(document, { subtree: true, childList: true })
return () => {
axeRunner.current = runAxe()
observer.disconnect()
}
}, []) // Empty dependency array to run the effect only once
useEffect(() => {
const runAxeFunction = axeRunner.current
runAxeFunction() // Run axe immediately on page load, route changes, and DOM mutations
}, [mutationCount])
return null
}
export default Axe
And import it in the App like this:
{!import.meta.env.PROD && <Axe />}