Home > Mobile >  React render on screen load with useState and URL params
React render on screen load with useState and URL params

Time:12-01

I am having a logical issue in React and still being a bit new, not sure what the right pattern is. Basically I have a screen with a flatlist that renders items. This screen can parse URL params to get a filter object via React Navigation props.route.params, but it can also accept no params (ie get all items).

The problem is on screen load, the filters are null, which is fine because they are allowed to be, but this triggers the flatlist to build right away (essentially, "show all items"). But then the URL params are eventually parsed (if present) so it re-renders right away.

I know there is a useRef kind of hack to prevent this sort of thing but again, the thing is filters is allowed to be null. Anyway I feel like this is a common issue but not sure what to do.

const Foo = (props: any) => {
    const [items, setItems] = React.useState<any[]>([]);
    const [filters, setFilters] = React.useState<any | null>(null);

    // This will render twice on load
    // Once when filters is null (which is acceptable!)
    // then immediately once query params are parsed
    React.useState(() => {
        let temp = createItemsFromFilters(filters);
        setItems(temp);
    }, [filters]);

    React.useState(() => {
        let filterParams: any | null = null;
        if(props.route.params.filters){
            try {filterParams = JSON.parse(props.route.params.filters)}
            catch(e){}
        }
        setFilters(filterParams)
    }, []);

    return (
        <Flatlist
            data={items}
            //...
        />
    )
}

CodePudding user response:

From what I understand, you only want this operation to be done when the component is mounted, you can just simply perform it in the useEffect function, with an empty dependency array (so it will be triggered one time, once your component is mounted):

React.useEffect(() => {
    let filterParams: any | null = null;
    if(props.route.params.filters){
        try {filterParams = JSON.parse(props.route.params.filters)}
        catch(e){}
    }
    let temp = createItemsFromFilters(filterParams);
    setItems(temp);
    setFilters(filterParams)
}, []);

This way, you will have 2 render, instead of the 3 that you had in your example

  • Related