useState Array of Objects

61,842

Solution 1

Assuming that response can be added directly to result array, you can:

setResult(result => [...result, response]);

This will append the new response from the previous result state and by using array spread operator.

Solution 2

You could just pass the entire array into the hook and return the result as an array. You should also use useEffect for async logic. I rewrote your code to process all 3 fields at once:

const useCableMatch = (searchInput) => {
  const [result, setResult] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);
  const client = useApolloClient();

  useEffect((searchInput) => {
     setIsError(false);
     setIsLoading(true);
     let response
     for(let field of searchInput){
        try {
           const { data } = await client.query({
              query: GET_VALID_CABLE,
              variables: { pn: `%${field}%` },
           });

           response = { ...data };
         } catch (error) {
             setIsError(true);
         }
     }
     setResult(current => {query, ...current, ...response);
     setIsLoading(false);
   };
  }, [searchInput])

  return [{ result, isLoading, isError }];
};
Share:
61,842
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    I have a search box that I can copy and paste a column from excel. I parse the input and generate an array of the entries.

    I am then mapping over the entries and calling a custom hook with each item to fetch some data from my graphql endpoint.

    For example:

    3 entries are provided from the search box:

    ["D38999/26", "LJT06RE25-61PA", "D38999/46FJ61AA"]

    The fetchData function receives one of these items at a time as the query parameter. Currently, this process would return 3 separate objects as such:

    {query: "D38999/26", cables: Array(35)}
    {query: "LJT06RE25-61PA", cables: Array(1)}
    {query: "D38999/46FJ61AA", cables: Array(1)}
    

    How do I set up a react hook to allow me to append each object into the result State as an array of objects?

    My end goal would be an array of objects like this:

    [
    {query: "D38999/26", cables: Array(35)},
    {query: "LJT06RE25-61PA", cables: Array(1)},
    {query: "D38999/46FJ61AA", cables: Array(1)}
    ]
    

    This is my current custom hook to resolve my API endpoint

    const useCableMatch = () => {
      const [result, setResult] = useState([]);
      const [isLoading, setIsLoading] = useState(false);
      const [isError, setIsError] = useState(false);
      const client = useApolloClient();
    
      const fetchData = async query => {
        setIsError(false);
        setIsLoading(true);
        try {
          const { data } = await client.query({
            query: GET_VALID_CABLE,
            variables: { pn: `%${query}%` },
          });
    
          const response = { query, ...data };
          console.log('response:', response);
    
          setResult(response);
        } catch (error) {
          setIsError(true);
        }
        setIsLoading(false);
      };
    
      return [{ result, isLoading, isError }, fetchData];
    };
    

    Currently setResult is set up to only return a single object from response. I would like to return an array with each object generated appended to the existing array of objects.

  • Admin
    Admin over 4 years
    This worked! I'm curious why setResult(result => [...result, response]); But this does not.. setResult([...result, response]);
  • Joseph D.
    Joseph D. over 4 years
    @JeremyLondon for setting the state is asynchronous. That notation is making sure to use the previous state of result.
  • Fakeer
    Fakeer almost 4 years
    upvoted. also if you update some value deep in result and need a rerender you can just do setResult( result => [...result] ). consider it a nudge to cause a render
  • Rob
    Rob over 3 years
    Thanks for this. I was struggling with why my child component would not update when I was using .push() to add to the existing state array and trying to set that in its state. It would work but my child component depending on the array was not immediately re-rendering as expected. (It would on a subsequent render or a force render).
  • Jonathan E. Emmett
    Jonathan E. Emmett about 2 years
    Well hell I learned something new today. Thanks for that.