In my existing react component, I need to render another react component for a specific time period. As soon as the parent component mounts/or data loads, the new-component (or child component) should be visible after 1-2 seconds and then after another few seconds, the new-component should be hidden. This needs to be done only if there is no data available.
This is what currently I've tried to achieve:
import React, { useState, useEffect } from "react";
function App() {
const [showComponent, setShowComponent] = useState(false);
const sampleData = [];
useEffect(() => {
if (sampleData.length === 0) {
setTimeout(() => {
setShowComponent(true);
}, 1000);
}
}, [sampleData]);
useEffect(() => {
setTimeout(() => {
setShowComponent(false);
}, 4000);
}, []);
const componentTwo = () => {
return <h2>found error</h2>;
};
return <>First component mounted{showComponent && componentTwo()}</>;
}
export default App;
The current implementation is not working as expected. The new-component renders in a blink fashion.
Here is the working snippet attached:
Any help to resolve this is appreciated!
Every time App renders, you create a brand new sampleData array. It may be an empty array each time, but it's a different empty array. Since it's different, the useEffect needs to rerun every time, which means that after every render, you set a timeout to go off in 1 second and show the component.
If this is just a mock array that will never change, then move it outside of App so it's only created once:
const sampleData = [];
function App() {
// ...
}
Or, you can turn it into a state value:
function App() {
const [showComponent, setShowComponent] = useState(false);
const [sampleData, setSampleData] = useState([]);
// ...
}
I have modified the code to work, hope this how you are expecting it to work.
import React, { useState, useEffect } from "react";
const sampleData = [];
// this has to be out side or passed as a prop
/*
reason: when the component render (caued when calling setShowComponent)
a new reference is created for "sampleData", this cause the useEffect run every time the component re-renders,
resulting "<h2>found error</h2>" to flicker.
*/
function App() {
const [showComponent, setShowComponent] = useState(false);
useEffect(() => {
if (sampleData.length === 0) {
const toRef = setTimeout(() => {
setShowComponent(true);
clearTimeout(toRef);
// it is good practice to clear the timeout (but I am not sure why)
}, 1000);
}
}, [sampleData]);
useEffect(() => {
if (showComponent) {
const toRef = setTimeout(() => {
setShowComponent(false);
clearTimeout(toRef);
}, 4000);
}
}, [showComponent]);
const componentTwo = () => {
return <h2>found error</h2>;
};
return <>First component mounted{showComponent && componentTwo()}</>;
}
export default App;
You can try this for conditional rendering.
import { useEffect, useState } from "react";
import "./styles.css";
const LoadingComponent = () => <div>Loading...</div>;
export default function App() {
const [isLoading, setLoading] = useState(true);
const [isError, setIsError] = useState(false);
const onLoadEffect = () => {
setTimeout(() => {
setLoading(false);
}, 2000);
setTimeout(() => {
setIsError(true);
}, 10000);
};
useEffect(onLoadEffect, []);
if (isLoading) {
return <LoadingComponent />;
}
return (
<div className="App">
{isError ? (
<div style={{ color: "red" }}>Something went wrong</div>
) : (
<div>Data that you want to display</div>
)}
</div>
);
}