skip to Main Content

I have a state, which is an object, that consists of
ìd: [{}, {}]
It can only be 2 key/value pairs in my state like

{
  243: [{}, {}, {}, ..],
  123: [{}, {}, ..],
}

The way Im doing it, its not limiting it to max 2 key/val pairs. How can I achieve that?

const App = ({ids}) => {
  const [data, setData] = useState<Record<number, Record[]>>({});
  useEffect(() => {
    const callAPI = async () => {
      ids.forEach(id => {
        const result = await axios.post("example.com", {id});
        setData((prev) => ({
          ...prev,
          [id]: result ?? [],
        }));
      })
    }
    callAPI()
  })
}

2

Answers


  1. Hi as far as I understand your question I would use a type to specify the ids.
    It seems you’re using Types already. So defining ids as a Tuple might solve that issue.
    With this Type you can enforce that the provided Ids are always exactly two numbers; no more no less.

    type Ids = [number, number];
    type AppProps = {
      ids: Ids
    }
    
    const App = ({ids}: AppProps) => {
      const [data, setData] = useState<Record<number, Record[]>>({});
      useEffect(() => {
        const callAPI = async () => {
          ids.forEach(id => {
            const result = await axios.post("example.com", {id});
            setData((prev) => ({
              ...prev,
              [id]: result ?? [],
            }));
          })
        }
        callAPI()
      })
    }
    

    If you want to allow 0-2 ids you can make the numbers optional with "?"

    type Ids = [number?, number?]
    
    const value: Ids = [] // valid
    const value1: Ids = [2] // valid
    const value2: Ids = [2, 3] // valid
    const value3: Ids = [2, 3, 4] // invalid
    

    EDIT:
    I think you need to clarify some things on a business level before the implementation can be done.
    Lets say you to use the type to limit the amount of provided IDs to the callApi function to max 2:

    If the current state is empty then it’s easy. Just add the IDs and their results to the state. Also if the current state holds 1 Entry and you call callAPI with just 1 ID, then the new ID gets added to the state with its result.
    But if you don’t want to reset the state every time you do a new call to callAPI (which I would assume based on your spread operator) there are the following cases to clarify on a business level in oder to provide a proper implementation.

    1. Current state holds n Items & you call callAPI with 2 IDs: You obviously need to replace the existing ID and their Values with the new ones since you want max. 2 entries.
    2. Current state holds 2 Items & you call callAPI with 1 IDs: Now if the provided ID exits in the state then you can simply update its value. BUT if the ID does not exist how do you decide which existing entry to override?

    If you can answer that question then you could translate that logic into code. When provided 2 IDs then simply replace the state. When Provided 1 ID then check the current state and either simply add the id and its state or replace one of the existing ids.

    Login or Signup to reply.
  2. Please try this way:

    a. Create an array of two promises only.
    These promises should only be with respect to the two ids in the array of ids which is the props to the application object.

    b. fulfil these two promises. The promise.all utility may be used to fulfil the promises.

    c. Update State as an when each promise will fulfil. The state updater function is to define as it takes the previous state value, and its body should append the key/value pairs.

    d. Display the keys and values. As each key has an array of objects as its value, there is a nested mapping is required to access the values.

    Note : Please note that the API fetch has been mocked here with the setTimeout async method and a hard-coded set of values. This is for brevity of the code

    Full listing of the code following the above approach.

    App.js

    import { useState, useEffect } from 'react';
    import DBdata from './data/data';
    
    function App({ ids }) {
      const [data, setData] = useState({});
    
      useEffect(() => {
        // creating an array of promises
        const arrayOfPromises = ids
          .filter((item, index) => index < 2)
          .map(
            (id, index) =>
              new Promise((resolve, reject) =>
                setTimeout(() => {
                  resolve({ [id]: [...DBdata[id]] });
                }, 1000)
              )
          );
        // fulfilling all promises
        (async () => {
          const tempData = await Promise.all(arrayOfPromises);
          // updating the state with a state updater
          tempData.map((item) => setData((prevItem) => ({ ...prevItem, ...item })));
        })();
      }, []);
      return (
        // displaying keys and values
        <>
          {Object.keys(data).map((key) => (
            <li key={key}>
              {key} : values :{' '}
              {data[key].map(
                (i, index) => i.name + (index < data[key].length - 1 ? ', ' : '')
              )}{' '}
            </li>
          ))}
        </>
      );
    }
    
    export default App;
    

    index.js

    import React, { StrictMode } from 'react';
    import { createRoot } from 'react-dom/client';
    import DBdata from './data/data';
    
    import App from './App';
    
    const root = createRoot(document.getElementById('root'));
    root.render(
      <StrictMode>
        <App ids={Object.keys(DBdata)} />
      </StrictMode>
    );
    

    data.js

    const DBdata = {
      243: [{ name: 'a' }, { name: 'b' }, { name: 'c' }],
      123: [{ name: 'aa' }, { name: 'bb' }, { name: 'cc' }, { name: 'dd' }],
      111: [{ name: 'aaa' }, { name: 'bbb' }, { name: 'ccc' }],
      222: [{ name: 'aaaa' }, { name: 'bbbb' }, { name: 'cccc' }],
      333: [{}, {}, {}, {}, {}],
    };
    
    export default DBdata;
    

    Test run

    Browser display on loading the App

    Browser display on loading the App

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search