admin管理员组

文章数量:1405392

In my existing react ponent, I need to render another react ponent for a specific time period. As soon as the parent ponent mounts/or data loads, the new-ponent (or child ponent) should be visible after 1-2 seconds and then after another few seconds, the new-ponent 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 ponentTwo = () => {
    return <h2>found error</h2>;
  };

  return <>First ponent mounted{showComponent && ponentTwo()}</>;
}

export default App;

The current implementation is not working as expected. The new-ponent renders in a blink fashion.

Here is the working snippet attached:

Any help to resolve this is appreciated!

In my existing react ponent, I need to render another react ponent for a specific time period. As soon as the parent ponent mounts/or data loads, the new-ponent (or child ponent) should be visible after 1-2 seconds and then after another few seconds, the new-ponent 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 ponentTwo = () => {
    return <h2>found error</h2>;
  };

  return <>First ponent mounted{showComponent && ponentTwo()}</>;
}

export default App;

The current implementation is not working as expected. The new-ponent renders in a blink fashion.

Here is the working snippet attached:

Any help to resolve this is appreciated!

Share Improve this question edited Feb 11, 2022 at 19:01 program_bumble_bee asked Feb 11, 2022 at 14:42 program_bumble_beeprogram_bumble_bee 3053 gold badges30 silver badges69 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 2

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 ponent render (caued when calling setShowComponent) 
a new reference is created for "sampleData", this cause the useEffect run every time the ponent 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 ponentTwo = () => {
    return <h2>found error</h2>;
  };

  return <>First ponent mounted{showComponent && ponentTwo()}</>;
}

export default App;

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 ponent.

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([]);
  // ...
}

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>
    );
}

I needed to do imperatively control rendering an animation ponent and make it disappear a few seconds later. I ended up writing a very simple custom hook for this. Here's a link to a sandbox.

NOTE: this is not a full solution for the OP's exact use case. It simply abstracts a few key parts of the general problem:

  1. Imperatively control a conditional render
  2. Make the conditional "expire" after duration number of milliseconds.

本文标签: javascriptReact render component only for few secondsStack Overflow