useState Array of Objects
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 }];
};
Admin
Updated on July 09, 2022Comments
-
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 over 4 yearsThis worked! I'm curious why
setResult(result => [...result, response]);
But this does not..setResult([...result, response]);
-
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 almost 4 yearsupvoted. also if you update some value deep in
result
and need a rerender you can just dosetResult( result => [...result] )
. consider it a nudge to cause a render -
Rob over 3 yearsThanks 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 about 2 yearsWell hell I learned something new today. Thanks for that.