Spaces:
Running
Running
CardioScreen AI commited on
Commit Β·
8f78b71
1
Parent(s): 4a627f0
fix: React hooks order violation (useState before useEffect)
Browse files- webapp/src/App.jsx +13 -9
webapp/src/App.jsx
CHANGED
|
@@ -399,6 +399,7 @@ function AudioTrimmer({ waveform, duration, onAnalyze, onSkip }) {
|
|
| 399 |
const API_URL = (import.meta.env.VITE_API_URL) ?? "http://127.0.0.1:8000/analyze";
|
| 400 |
|
| 401 |
function App() {
|
|
|
|
| 402 |
const [appState, setAppState] = useState('upload');
|
| 403 |
const [patientData, setPatientData] = useState({ dogId: '', breed: '', age: '' });
|
| 404 |
const [analysisResult, setAnalysisResult] = useState(null);
|
|
@@ -406,19 +407,14 @@ function App() {
|
|
| 406 |
const [recordingTime, setRecordingTime] = useState(0);
|
| 407 |
const [audioBlob, setAudioBlob] = useState(null);
|
| 408 |
const [audioUrl, setAudioUrl] = useState(null);
|
|
|
|
|
|
|
| 409 |
const [theme, setTheme] = useState('dark');
|
| 410 |
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
| 411 |
|
| 412 |
-
//
|
| 413 |
-
|
| 414 |
-
document.documentElement.setAttribute('data-theme', theme);
|
| 415 |
-
}, [theme]);
|
| 416 |
|
| 417 |
-
const toggleTheme = () => setTheme(t => t === 'dark' ? 'light' : 'dark');
|
| 418 |
-
const closeMobileNav = () => setMobileNavOpen(false);
|
| 419 |
-
const [trimWaveform, setTrimWaveform] = useState(null);
|
| 420 |
-
const [trimDuration, setTrimDuration] = useState(0);
|
| 421 |
-
const rawAudioBuffer = useRef(null); // holds decoded AudioBuffer for trimming
|
| 422 |
|
| 423 |
const audioContextRef = useRef(null);
|
| 424 |
const analyserRef = useRef(null);
|
|
@@ -432,6 +428,14 @@ function App() {
|
|
| 432 |
const waveformCanvasRef = useRef(null);
|
| 433 |
const audioRef = useRef(null);
|
| 434 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 435 |
const stopRecording = () => {
|
| 436 |
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {
|
| 437 |
mediaRecorderRef.current.stop();
|
|
|
|
| 399 |
const API_URL = (import.meta.env.VITE_API_URL) ?? "http://127.0.0.1:8000/analyze";
|
| 400 |
|
| 401 |
function App() {
|
| 402 |
+
// ββ All useState hooks first (React rules of hooks) ββββββ
|
| 403 |
const [appState, setAppState] = useState('upload');
|
| 404 |
const [patientData, setPatientData] = useState({ dogId: '', breed: '', age: '' });
|
| 405 |
const [analysisResult, setAnalysisResult] = useState(null);
|
|
|
|
| 407 |
const [recordingTime, setRecordingTime] = useState(0);
|
| 408 |
const [audioBlob, setAudioBlob] = useState(null);
|
| 409 |
const [audioUrl, setAudioUrl] = useState(null);
|
| 410 |
+
const [trimWaveform, setTrimWaveform] = useState(null);
|
| 411 |
+
const [trimDuration, setTrimDuration] = useState(0);
|
| 412 |
const [theme, setTheme] = useState('dark');
|
| 413 |
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
| 414 |
|
| 415 |
+
// ββ All useRef hooks next βββββββββββββββββββββββββββββββββ
|
| 416 |
+
const rawAudioBuffer = useRef(null);
|
|
|
|
|
|
|
| 417 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 418 |
|
| 419 |
const audioContextRef = useRef(null);
|
| 420 |
const analyserRef = useRef(null);
|
|
|
|
| 428 |
const waveformCanvasRef = useRef(null);
|
| 429 |
const audioRef = useRef(null);
|
| 430 |
|
| 431 |
+
// Apply theme attribute to <html> element
|
| 432 |
+
useEffect(() => {
|
| 433 |
+
document.documentElement.setAttribute('data-theme', theme);
|
| 434 |
+
}, [theme]);
|
| 435 |
+
|
| 436 |
+
const toggleTheme = () => setTheme(t => t === 'dark' ? 'light' : 'dark');
|
| 437 |
+
const closeMobileNav = () => setMobileNavOpen(false);
|
| 438 |
+
|
| 439 |
const stopRecording = () => {
|
| 440 |
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {
|
| 441 |
mediaRecorderRef.current.stop();
|