1

I have a loader which shows loading message when passed a string, but when passed an array I want to show multiple messages one after another looping through messages array.

const messages = ['fetching from sources...', 'loading account...'];

<Loader message={messages}/>

const Loader = (Props) => {
    const { message } = props;


    const renderMessages = (msgs) => {

        console.log(msgs);
        return msgs.forEach((msg, i) => {
            setTimeout(() => {
                return <Message>{msg}</Message>;
            }, 500);
        });
    };

    return (
        <LoaderContainer>
            <LoaderSvg width="120" height="120" viewBox="0 0 100 100" />
            {(Array.isArray(message)) ? renderMessages(message) : <Message>{message}</Message>}

        </LoaderContainer>
    );
};
2
  • Welcome to StackOverflow. What have you tried/investigated? Commented Sep 4, 2019 at 15:07
  • 2
    @JeroenHeier Well the code clearly shows what OP tried, doesn't it? Commented Sep 4, 2019 at 15:08

4 Answers 4

5

Here's an example of what could work for you: https://codesandbox.io/s/loop-through-array-with-react-d5tlc (I would suggest reviewing it for edge cases but the core functionality should be close to what you're looking for).

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const messages = ["fetching from sources...", "loading account..."];

const Loader = props => {
  const { messages } = props;
  // Default to the first message passed
  const [messageIndex, setMessageIndex] = React.useState(0);

  React.useEffect(() => {
    // Move on to the next message every `n` milliseconds
    let timeout;
    if (messageIndex < messages.length - 1) {
      timeout = setTimeout(() => setMessageIndex(messageIndex + 1), 1000);
    }

    return () => {
      clearTimeout(timeout);
    };
  }, [messages, messageIndex]);

  return <div>{messages[messageIndex]}</div>;
};

function App() {
  return (
    <div className="App">
      <Loader messages={messages} />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Sign up to request clarification or add additional context in comments.

2 Comments

Nice, that's how I would do it. I don't think setMessageIndex needs to be in the useEffect dep array
@WillJenkins ah yea, you're right. I thought it was hitting the exhaustive dep check linting warning but I was wrong. I update the example to remove setMessageIndex from the dep array.
0

A functional component has to return the jsx to render. What you are trying to do does not work. In case of an array of messages you are returning msgs.forEach(...) but Array.prototype.forEach does not return an array but undefined.

You will need to use state to queue up the messages one by one and render the contents of that state instead.

Comments

-1

You can append message in a variable and return that variable in renderMessage function

const renderMessages = (msgs) => {
    let msgList = ""
    console.log(msgs);
    return msgs.forEach((msg, i) => {
        msgList = msgList + "/n" + msg
        setTimeout(() => {
            return <Message>{msgList}</Message>;
        }, 500);
    });
};

/n will show next message in new line

Comments

-1

What does you program not do as expected? Do the messages not show?

If you want to render some element while iterating through an aray, i would advise to use array.map() rather than array.forEach().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.