skip to Main Content

I have a group of react-native components that have similar interfaces. The important method in the interface is the run method. Users can execute this run method by pressing an action button for each of the components or by pressing an action button in the parent level, that will iterate through each of these similar components using their ref and call the run method. Here is a simplified version of the setup.

const Test1 = forwardRef((props, ref) => {
  const [importantState, setimportantState] = useState('initial')
  useImperativeHandle(ref, () => ({
    run: run,
  }))

  const run = async () => {
    // This function will open a modal
    //  where users will eventually change the important state
    openInteractionModal()

    // The idea of this promiss is to settle when the users
    // eventually change the importantState thorugh thier interaction
    // It does so by checking the state every 100 miliseconds
    // This however is a problem as a result of the setInterval function will
    // inclose the initial state instead of getting the new value each time
    return new Promise((resolve, reject) => {
      let interval = setInterval(() => {
        if (importantStat === 'complete') {
          resolve('success')
          clearInterval(interval)
        } else if (importantStat === 'failed') {
          reject('failed')
          clearInterval(interval)
        }
      }, 100)
    })
  }
  return (
    <>
      <Button title="run" onPress={run} />
    </>
  )
})

const parentComponent = () => {
  const test1Ref = userRef(null)
  const test2Ref = userRef(null)
  const test3Ref = userRef(null)

  const testRefs = [test1Ref, test2Ref, test3Ref]

  const autoRun = async () => {
    testRefs.forEach(ref => {
        await ref?.current.run()
    });
  }

  return (
    <>
      <Button title="Auto run" onPress={autoRun} />
      <Test1 ref={test1Ref} />,
      <Test2 ref={test2Ref} />,
      <Test3 ref={test3Ref} />,
    </>
  )
}

The problem I am having right now is the promise I am returning from these individual components never settles as a result of the closure I mentioned above in the comments. Is there a way to overcome this closure, or is there a better react-native pattern that I am using right now?

2

Answers


  1. Create a ref and store the status in that instead of the state of the Test1 component.

    Like that

    const importantState = useRef(null);
    

    Set value in the current of the ref

    importantState.current="complete"
    

    Later use it in the setInterval like

    if(importantState.current === "complete")
    
    Login or Signup to reply.
  2. Don’t go polling. Instead, pass the resolve function as an argument to openInteractionModal, and call it together with setImportantState from the modal dialog.


    If that is for some reason not possible, you can use a ref to store the resolve function and run it from an effect when the state changes:

    const onImportantStateChange = useRef();
    useEffect(() => {
      if (!onImportantStateChange.current) return;
      if (importantState === 'complete') {
        onImportantStateChange.current('success');
        onImportantStateChange.current = undefined;
      } else if (importantState === 'failed') {
        onImportantStateChange.current(Promise.reject(new Error('failure')));
        onImportantStateChange.current = undefined;
      }
    }, [importantState])
    const run = async () => {
      return new Promise(resolve => {
        onImportantStateChange.current = resolve;
    
        // This function will open a modal
        //  where users will eventually change the important state
        openInteractionModal();
      });
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search