Is there a way to do an api call only once in react functional component?

2020-03-26 reactjs

Sorry if it's a beginner question>

I am trying to use Functional Component, as I was doing Class Component all the time.

I have a simple component that should load a list from a server, and display it.

The component looks like this (I simplified a bit so sorry if there is a type) :

const ItemRelationsList = (props: ItemRelationsListProps): JSX.Element => {
    const [getList, setList] = useState([]);

    const loadRelation = (): void => {
        HttpService.GetAsync<getListRequest, getListResponse>('getList',{
            // params
        }).subscribe(res => {
            setList(res.data.list);
        });
    }
    loadRelation();


  return (
    <>
        <Table
            columns={columns}
            dataSource={getList}
        >
        </Table>
    </>
  )
}

thew problem I face is that everytime I use setList, the component is redraw, so the http call is reexecute.

Is there a way to prevent that other than use a class component ?

Answers

use useEffect

If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works.

const ItemRelationsList = (props: ItemRelationsListProps): JSX.Element => {
    const [getList, setList] = useState([]);

    // componentDidMount
    useEffect(() => {
        loadRelation()
    }, [])

    const loadRelation = (): void => {
        HttpService.GetAsync<getListRequest, getListResponse>('getList',{
            // params
        }).subscribe(res => {
            setList(res.data.list);
        });
    }

    return (
        <>
            <Table
                columns={columns}
                dataSource={getList}
            >
            </Table>
        </>
    )
}

useEffect(yourCallback, []) - will trigger the callback only after the first render.

Read the Docs hooks-effect

This is related to How to call loading function with React useEffect only once

Related