'React Typescript. The right way to push new objects form api to array with existing objects without repeating them

I have a custom hook where I call 16 subreddits at the time because I want to implement an infinite scroll. When the url page parameter change I want to add the new data to the array witch then I map. But I cant find the right way to do it with typescript. Can some of you guys show me the right way?

The types:

export type Subreddits = [Subreddit];
export type Subreddit = {
id: string;
title: string;
description: string;
}; 

The Hook:

function useSubreddit() {
  let [subredditData, setSubredditData] = useState<any>([]);
  const [loadingSubbredits, setLoadingSubreddits] = useState(false);
  const [subredditError, setSubredditError] = useState(null);
  const dispatch = useDispatch();
  const url =
    "https://6040c786f34cf600173c8cb7.mockapi.io/subreddits?page=1&limit=16";

  useEffect(() => {
    setLoadingSubreddits(true);
    axios
      .get(url)
      .then((response) => {
        setSubredditData(
          (subredditData = [ new Set([...subredditData, ...response.data])])
        );
        dispatch(setSubredditsData(response.data));
      })
      .catch((err) => {
        setSubredditError(err);
      })
      .finally(() => setLoadingSubreddits(false));
  }, [url]);

  return { loadingSubbredits, subredditError, subredditData };
}

export default useSubreddit;


Solution 1:[1]

This is the right way to add new item to set:

setSubredditData((
    { subredditData }) => ({
        subredditData: new Set(subredditData).add(response.data)
      })
);

Solution 2:[2]

Change subredditData type to Array

const [subredditData, setSubredditData] = useState<Array>([])

Then use;

setSubredditData(subredditData => [...subredditData, ...response.data])

Ideally you should define the type of response object so Typescript knows what kind of data it has;

.then((response: ResponseType) => {

Working example: codesandbox

Solution 3:[3]

import { useState, useEffect } from "react";
import axios from "axios";

function useSubreddit() {
  let [subredditData, setSubredditData] = useState({});
  const [loadingSubbredits, setLoadingSubreddits] = useState(false);
  const [subredditError, setSubredditError] = useState(null);
  //console.log(subredditData);
  const url =
    "https://6040c786f34cf600173c8cb7.mockapi.io/subreddits?page=1&limit=16";

  useEffect(() => { 
    setLoadingSubreddits(true);
    axios
      .get(url)
      .then((response) => {
        const result = response.data?.reduce((prev,curr) => ({ ...prev, ...{ [curr.id]: curr }}),{});
       
        setSubredditData((subredditData) => ({ ...subredditData, ...result }));
      })
      .catch((err) => {
        setSubredditError(err);
      })
      .finally(() => setLoadingSubreddits(false));
  }, [url]);

  return { loadingSubbredits, subredditError, subredditData:Object.values(subredditData) };
}

export default useSubreddit;

working example: https://codesandbox.io/s/musing-brown-9nf7ne?file=/src/App.js

Solution 4:[4]

I found the solution

function useSubreddit() {
  const [subredditData, setSubredditData] = useState<Array<any>>([])
  const [loadingSubbredits, setLoadingSubreddits] = useState(false);
  const [subredditError, setSubredditError] = useState(null);
  const dispatch = useDispatch();
  const url =
    "https://6040c786f34cf600173c8cb7.mockapi.io/subreddits?page=1&limit=4";

  useEffect(() => {
    setLoadingSubreddits(true);
    axios
      .get(url)
      .then((response: SubredditsResponse) => {
        setSubredditData(Array.from( new Set([ ...subredditData, ...response.data])))
        dispatch(setSubredditsData(response.data));
      })
      .catch((err) => {
        setSubredditError(err);
      })
      .finally(() => setLoadingSubreddits(false));
  }, [url]);

  return { loadingSubbredits, subredditError, subredditData };
}

export default useSubreddit;

Thank you for your help guys

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ChamRun
Solution 2
Solution 3
Solution 4 Oren Papa