admin管理员组

文章数量:1316654

  const fetcher = (url: string) => fetch(url).then((r) => r.json());

  const { data, error } = useSWR(
    ";,
    fetcher,
  );

is there any way to add data in a useState hook like this

  const fetcher = (url: string) => fetch(url).then((r) => r.json());

  const { data, error } = useSWR(
    ";,
    fetcher,
  );

const [memes,setMemes]=useState(data);

cause I want to concat the data at some point for inifnite scrolling

  const fetcher = (url: string) => fetch(url).then((r) => r.json());

  const { data, error } = useSWR(
    "https://some./api",
    fetcher,
  );

is there any way to add data in a useState hook like this

  const fetcher = (url: string) => fetch(url).then((r) => r.json());

  const { data, error } = useSWR(
    "https://meme-api.herokuapp./gimme/5",
    fetcher,
  );

const [memes,setMemes]=useState(data);

cause I want to concat the data at some point for inifnite scrolling

Share Improve this question asked Sep 27, 2021 at 11:09 Jatin HemnaniJatin Hemnani 3212 silver badges8 bronze badges 6
  • Side note: Your fetcher function is falling prey to a footgun in the fetch API I describe here. Before calling json, you probably want to check whether the HTTP request was successful (fetch doesn't reject on HTTP errors, only network errors). So: const fetcher = (url: string) => fetch(url).then((r) => { if (!r.ok) { throw new Error(`HTTP error ${r.status}`); } return r.json(); }); – T.J. Crowder Commented Sep 27, 2021 at 11:18
  • 1 FWIW, useSWR doesn't immediately seem to make sense with something like https://meme-api.herokuapp./gimme/5 that always provides a new set of responses when you send it a request. – T.J. Crowder Commented Sep 27, 2021 at 11:23
  • You can but only when your ponent mounts, because you need to wait for the api response in useSWR(), add the data as dependency so whenever it changes, it'll rerender. – kmp Commented Sep 27, 2021 at 11:27
  • @T.J.Crowder what if I want to contact the data every new request – Jatin Hemnani Commented Sep 27, 2021 at 13:52
  • @JatinHemnani - What does "contact the data every new request" mean? – T.J. Crowder Commented Sep 27, 2021 at 13:55
 |  Show 1 more ment

2 Answers 2

Reset to default 5

The fastest solution to transfer data from one variable to another is to use an useEffect hook. When data changes, update memes.

useEffect(() => { setMemes(data); }, [data])

Infinite scroling

A better solution would be to use SWR provided solutions for infinite scrolling. You have different options documented here.

Plain fetch

In this case, you can also consider using directly the fetch function and appending data to the memes list directly:

const [ memes, setMemes ] = useState([]);

async function fetchAnotherPage() {
    const data = (await fetch('https://meme-api.herokuapp./gimme/5')).json();
    setMemes(value => [...value, ...data.memes]);
}

useEffect(() => fetchAnotherPage(), []);

Since https://meme-api.herokuapp./gimme/5 always returns new data for each call, useSWR isn't a good fit for this and, moreover, the fact it retrieves from cache and gives that to your code and then revalidates and (possibly) calls your code to update, without telling you whether it's the first result or an update, makes it very hard to do what you're describing.

Instead, I'd just use fetch directly and not try to do the SWR thing; see ments:

// Start with no memes
const [memes,setMemes] = useState([]);

// Use a ref to track an `AbortController` so we can:
// A) avoid overlapping fetches, and
// B) abort the current `fetch` operation (if any) on unmount
const fetchControllerRef = useRef(null);

// A function to fetch memes
const fetchMoreMemes = () => {
    if (!fetchControllerRef.current) {
        fetchControllerRef.current = new AbortController();
        fetch("https://meme-api.herokuapp./gimme/5", {signal: fetchControllerRef.current.signal})
        .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP error ${response.status}`);
            }
            return response.json();
        })
        .then(newMemes => {
            setMemes(memes => memes.concat(newMemes.memes));
        })
        .catch(error => {
            // ...handle/report error...
        })
        .finally(() => {
            fetchControllerRef.current = null;
        });
    }
};

// Fetch the first batch of memes
useEffect(() => {
    fetchMoreMemes();
    return () => {
        // Cancel the current `fetch` (if any) when the ponent is unmounted
        fetchControllerRef.current?.abort();
    };
}, []);

When you want to fetch more memes, call fetchMoreMemes.

Live Example:

const {useState, useEffect, useRef} = React;

const Example = () => {
    // Start with no memes
    const [memes,setMemes] = useState([]);

    // Use a ref to track an `AbortController` so we can:
    // A) avoid overlapping fetches, and
    // B) abort the current `fetch` operation (if any) on unmount
    const fetchControllerRef = useRef(null);

    // A function to fetch memes
    const fetchMoreMemes = () => {
        if (!fetchControllerRef.current) {
            fetchControllerRef.current = new AbortController();
            fetch("https://meme-api.herokuapp./gimme/5", {signal: fetchControllerRef.current.signal})
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP error ${response.status}`);
                }
                return response.json();
            })
            .then(newMemes => {
                // I'm filtering out NSFW ones here on SO
                setMemes(memes => memes.concat(newMemes.memes.filter(({nsfw}) => !nsfw)));
            })
            .catch(error => {
                // ...handle/report error...
            })
            .finally(() => {
                fetchControllerRef.current = null;
            });
        }
    };

    // Fetch the first batch of memes
    useEffect(() => {
        fetchMoreMemes();
        return () => {
            // Cancel the current `fetch` (if any) when the ponent is unmounted
            fetchControllerRef.current && fetchControllerRef.current.abort();
        };
    }, []);
    
    const message = memes.length === 1 ? "1 meme:" : `${memes.length} memes:`;
    return <div>
        <div>{message} <input type="button" value="More" onClick={fetchMoreMemes}/></div>
        <ul>
            {/* `index` as key is ONLY valid because our array only grows */}
            {memes.map(({postLink}, index) => <li key={index}>{postLink}</li>)}
        </ul>
    </div>
};


ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare./ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

本文标签: javascriptuse SWR data in useState HookStack Overflow