skip to Main Content

I understand React Native re-renders component in which setState is called.
In example as I tested, there are 7 re-renders per 7 setStates in useEffect codes:

  const pullData = async (numToPull, filterPull, sorterPull) => {
    setToSpin(true);
    const response = await AxiosPost(
      sc.Slink.getMailInbox,
      {
        page: 1,
        pageSize: numToPull,
        filterOption: [
          ...filterPull,
          {
            key: "isUnread",
            value: true,
          },
        ],
        sortOption: sorterPull,
      },
      { Authorization: ctxt.authInfo.tokenSF },
      { studio: ctxt.roomInfo.currentLoginRoom }
    );

    setToSpin(false);

    if (response.data.suc) {
      setShowList(response.data.data.items);
      setNumOfDataPulled(response.data.data.items.length);
      setSearchKey("");
      setCurrentFilter(filterPull);
      setCurrentSorter(sorterPull);
    } else setSmsg(response.data.msg);
  };

  useEffect(() => {
    pullData(sc.Snumber.numToPullMail, [], []);
  }, []);

I’m wondering is this a designed mechanism in React Native? or there are other ways to reduce render-times?

Above example is simple in my project though – I have some complex components in which have more than 20 setState in-used, also with ~10 functions in each component. If setState causes re-render 20+ times plus re-creation of functions, the resource waste is probably considerable…

I don’t want to use Redux, useCallback and would like know 1) is this normal in React Native world? (render 20 times for any component); 2) is there smarter way to avoid resource waste in virtual DOM comparision? (in example above, I didn’t see any reason have to render component 5 times for codes written in sequence

  setShowList(response.data.data.items);
  setNumOfDataPulled(response.data.data.items.length);
  setSearchKey("");
  setCurrentFilter(filterPull);
  setCurrentSorter(sorterPull);

)

Thanks!

2

Answers


  1. If you use react 18 (which was enabled by default in React Native 0.69), setting multiple states like this will do just one render:

    setToSpin(false);
    
    if (response.data.suc) {
      setShowList(response.data.data.items);
      setNumOfDataPulled(response.data.data.items.length);
      setSearchKey("");
      setCurrentFilter(filterPull);
      setCurrentSorter(sorterPull);
    } else setSmsg(response.data.msg);
    
    

    Prior to react 17, react could usually batch them together, but not always. One of those cases which did not work was the one you have in your example: in an async function after an await. For this case, each of the calls to set state would cause its own render, not a single batched one.

    In react 17 you can force these to be batched by the use of unstable_batchedUpdates:

    import { unstable_batchedUpdates } from 'react-native' // or in web, from 'react-dom'
    
    // ...
    
    unstable_batchedUpdates(() => {
      setToSpin(false);
    
      if (response.data.suc) {
        setShowList(response.data.data.items);
        setNumOfDataPulled(response.data.data.items.length);
        setSearchKey("");
        setCurrentFilter(filterPull);
        setCurrentSorter(sorterPull);
      } else setSmsg(response.data.msg);
    });
    
    
    Login or Signup to reply.
  2. The behavior you’re observing is a common characteristic of React and React Native, known as "reconciliation". When a component’s state changes, React checks to see if any of the component’s child elements need to be re-rendered. If any of the child elements need to be updated, then the entire component is re-rendered.

    In the example you provided, the component is re-rendered 7 times because there are 7 state updates triggered by the set functions inside the pullData function. This is a normal behavior in React and React Native, and it is how the framework ensures that the UI is always up-to-date with the application’s state.

    Here’s a way you could resolve this by React.Memo

    import React, { memo, useEffect, useState } from 'react';
    
    const MyComponent = memo(() => {
    const [showList, setShowList] = useState([]);
    const [numOfDataPulled, setNumOfDataPulled] = useState(0);
    const [searchKey, setSearchKey] = useState("");
    const [currentFilter, setCurrentFilter] = useState([]);
    const [currentSorter, setCurrentSorter] = useState([]);
    const [toSpin, setToSpin] = useState(false);
    
    const pullData = async (numToPull, filterPull, sorterPull) => {
        setToSpin(true);
        const response = await AxiosPost(
            sc.Slink.getMailInbox,
            {
                page: 1,
                pageSize: numToPull,
                filterOption: [
                    ...filterPull,
                    {
                        key: "isUnread",
                        value: true,
                    },
                ],
                sortOption: sorterPull,
            },
            { Authorization: ctxt.authInfo.tokenSF },
            { studio: ctxt.roomInfo.currentLoginRoom }
        );
    
        setToSpin(false);
    
        if (response.data.suc) {
            setShowList(response.data.data.items);
            setNumOfDataPulled(response.data.data.items.length);
            setSearchKey("");
            setCurrentFilter(filterPull);
            setCurrentSorter(sorterPull);
        } else setSmsg(response.data.msg);
    };
    
    useEffect(() => {
        pullData(sc.Snumber.numToPullMail, [], []);
    }, []);
    
    return (
        <div>
            // render your component here
        </div>
    );
    });
    
    export default MyComponent;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search