1

I have a little web application that uses axios to fetch some orders from the API. My problem is the new orders only appear when the page is refreshed, they do not update automatically.

Here is my useEffect hook:

useEffect(() => {
    setLoading(true);
    apiClient
      .getEvents()
      .then((res) => {
        console.log(res);
        setOrders(res.data);
        setLoading(false);
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);

And here is where I use axios:

import axios from "axios";

const username = "user";
const password = "pass";

const token = Buffer.from(`${username}:${password}`, "utf8").toString("base64");

const apiClient = axios.create({
  baseURL: "API URL",
  withCredentials: false,
  headers: {
    Accept: "application/json",
    "Content-Type": "application/json",
    Authorization: `Basic ${token}`,
  },
});

export default {
  getEvents() {
    return apiClient.get("/orders");
  },
  getEvent(order_id) {
    return apiClient.get("/orders/" + order_id);
  },
};
20
  • 1
    Can you share a Minimal, Complete, and Reproducible code example of the component using the useEffect? It would be better if we could see how the component is declaring "data" and using it. Commented Oct 1, 2020 at 22:36
  • This is my full component code: jsfiddle.net/1nv7bjek/2 Commented Oct 1, 2020 at 22:39
  • Does console.log(res) log what you expect? Is the page stuck "loading", or does the setLoading(false); stop that? Can you be more specific about what data isn't updating? Commented Oct 1, 2020 at 22:43
  • The data is loading on initial load of the website, but whenever I make a new order, I need to refresh the page in order to make the new order appear. Commented Oct 1, 2020 at 22:45
  • Hi, an observation about one line, you setLoading(false) only in then block, I recommend you to add finally block and setLoading(false) inside it. In case of error loading still be true Commented Oct 1, 2020 at 22:48

1 Answer 1

1

Your problem ist the useEffect-Hook itself.

useEffect(() => {
    setLoading(true);
    apiClient
      .getEvents()
      .then((res) => {
        console.log(res);
        setOrders(res.data);
        setLoading(false);
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);

You pass an empty array as the second argument here: }, []);. When you pass an empty array as second argument to useEffect, it will only run on first mount and then never again.

You can pass different variables in this parameter. In this case, useEffect will run, when of these variables change their value. So, for example, you could have a "Refresh" button which changes a state called refresh which you then pass as a second argument to useEffect.

const [refresh, setRefresh] = useState(false);

useEffect(() => {
    if(!refresh) return;
    setLoading(true);
    apiClient
      .getEvents()
      .then((res) => {
        console.log(res);
        setOrders(res.data);
        setLoading(false);
        setRefresh(false);
      })
      .catch((err) => {
        console.log(err);
      });
  }, [refresh]);

Just a simple example, it could be done better, of course.

Also, one hint: You can omit the second parameter, the dependency array, of useEffect, which would make it run on every update of your component. Don't do this. In most cases, you will end up in an infinite loop because most of the time you will update the state and cause the component to rerender within useEffect - in your case, using setLoading() would be enough.

Sign up to request clarification or add additional context in comments.

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.