Search code examples
reactjstypescriptreact-hooksuse-effect

Retrieve the latest data by using API link


Goal:
Every time when I press the Button 'Test' you always need to fetch fresh data from backend by using API link. Then it should be displayed on the modalform.

Problem:
When I change the text in the input box or delete all text and then closing the modal and then click on the button Test again. The latest changes of what I have done would display. It shouldn't be happening because you always should get the latest data from backend by using API link.

Question:
How should the code always retrieve the data by using api link when you always press on the button 'test'?

Stackblitz:
https://stackblitz.com/edit/react-ts-byxk6x?file=index.tsx

Thank you!


index.tsx

import React, { FC, useState } from 'react';
import { render } from 'react-dom';
import './style.css';
import { TestModalForm } from './TestModalForm';

interface AppProps {}
interface AppState {
  name: string;
}

const App: FC<AppProps> = () => {
  return (
    <div>
      <button data-bs-toggle="modal" data-bs-target="#myModal">
        Test
      </button>
      <br />

      <TestModalForm />
    </div>
  );
};

render(<App />, document.getElementById('root'));

TestModalForm.tsx

import React, { useState } from 'react';

export const TestModalForm = () => {
  const [inputid, setInputid] = useState('');
  const [inputTitle, setInputTitle] = useState('');

  React.useEffect(() => {
    async function FetchData() {
      var data = await fetch(
        'https://jsonplaceholder.typicode.com/todos/1'
      ).then((res) => {
        return res.json();
      });
      setInputid(data.id);
      setInputTitle(data.title);
    }

    FetchData();
  }, []);

  const handleIdInput = (e: any) => {
    setInputid(e.target.value);
  };

  const handleTitleInput = (e: any) => {
    setInputTitle(e.target.value);
  };

  // Reset Input Field handler
  const resetInputField = () => {
    setInputid('');
    setInputTitle('');
  };

  return (
    <div>
      <div
        className="modal"
        id="myModal"
        data-bs-backdrop="static"
        data-bs-keyboard="false"
        tabIndex={-1}
        aria-labelledby="staticBackdropLabel"
        aria-hidden="true"
      >
        <div className="modal-dialog">
          <div className="modal-content">
            <div className="modal-header">
              <h4 className="modal-title">TEST</h4>
              <button
                type="button"
                className="btn-close btn-close-white"
                data-bs-dismiss="modal"
              ></button>
            </div>
            <div className="modal-body">
              <input
                type="text"
                className="form-control"
                placeholder="Id"
                value={inputid}
                onChange={handleIdInput}
              />
              <br />
              <input
                type="text"
                className="form-control"
                placeholder="Title"
                value={inputTitle}
                onChange={handleTitleInput}
              />
              <br />
              <button className="form-control" onClick={resetInputField}>
                Reset
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

Solution

  • A simple solution would be to introduce some state to the App component, updated by the test button being clicked, that could be passed to the TestMOdalForm to be used as an useEffect dependency.

    It's also anti-pattern to mix async/await with Promise-chains. Pick one or the other.

    Example:

    const App: FC<AppProps> = () => {
      const [id, setId] = useState(0);
    
      return (
        <div>
          <button
            data-bs-toggle="modal"
            data-bs-target="#myModal"
            onClick={() => setId((c) => c + 1)} // <-- update state upon click
          >
            Test
          </button>
          <br />
    
          <TestModalForm id={id} /> // <-- pass state as prop
        </div>
      );
    };
    

    ...

    const TestModalForm = ({ id }) => { // <-- destructure prop
      ...
    
      React.useEffect(() => {
        async function fetchData() {
          try {
            const response = await fetch(
              'https://jsonplaceholder.typicode.com/todos/1'
            );
            const data = await response.json();
    
            setInputid(data.id);
            setInputTitle(data.title);
          } catch(error) {
            // handle any fetch rejections or other thrown errors
          }
        }
    
        fetchData();
      }, [id]); // <-- pass prop as dependency
    
      ...
    
      return (
        ...
      );
    };
    

    Edit retrieve-the-latest-data-by-using-api-link