1
votes

Consider the following:

I have a parent functional component with a nested child component,

function Parent(){
  const [isFlagTrue, setIsFlagIsTrue] = useState(false);

    const handleFlagChange = (bool) => setIsFlagIsTrue(bool)

    useEffect(() => {

    console.log("isFlagTrue ", isFlagTrue);
 }, [isFlagTrue])

  return (
    <Child handleFlagChange={handleFlagChange} />
  )
}

In the Child I'm making an async call to populate a data-table;

import { useDispatch } from 'react-redux';


function Child({handleFlagChange}) {

    const dispatch = useDispatch();
    const componentIsMounted = useRef(true)
    const [rows, setRows] = useState([]);

    useEffect(() => {

        if (currentProductItem && currentProductItem.value != null) {
            
               dispatch(getClientVariables(currentProductItem.value)).then(r => {
                rawData.current.Rows = r.payload;
                dispatch(getClientVariableTypesAll(currentProductItem.value)).then(r => {

                    rawData.current.ClientDataVariableTypes = r.payload.map(r => {
                        return {
                            value: r.ClientDataVariableTypeID,
                            label: r.ClientDataVariableTypeName
                        }
                    });;
                    setRows(rawData.current.Rows);
                    console.log('rawData', rawData);

                });
            });
        }
    }, [currentProductItem, justSavedNewVariableTypes, justSavedGrid]);

}

    useEffect(() => {
    console.log("typeof handleFlagChange ", typeof handleFlagChange);

    console.log("rows ", rows);

    // if (componentIsMounted.current) {
    //  var flag = rows.some(item => item.ClientDataVariableTypeName == null)
    //  handleFlagChange(flag)
    // }

    if (Array.isArray(rows) && typeof handleFlagChange != 'undefined') {
        console.log("foo ");
        var flag = rows.some(item => item.ClientDataVariableTypeName == null)
        handleFlagChange(flag)
    }
}, []);

useEffect(() => {
    return () => {
        componentIsMounted.current = false
    }
},[])
    
   ....other code & rendering    
    
}

I am expecting the isFlagTrue console in the useEffect of the parent to fire when the rows have been validated in the child by the return value of the some function on the array of rows.

I have tried two solutions one is insuring the <Child/> is mounted (and having the data call being full-filled) by setting a ref to true using useRef().

In Child: const componentIsMounted = useRef(true)

useEffect(() => {
    console.log("typeof handleFlagChange ", typeof handleFlagChange);


     if (componentIsMounted.current) {
       var flag = rows.some(item => item.ClientDataVariableTypeName == null)
       handleFlagChange(flag)
      }

}, []);

useEffect(() => {
    return () => {
        componentIsMounted.current = false
    }
},[])

But I get TypeError: handleFlagChange is not a function

So then I tried:

useEffect(() => {
        console.log("typeof handleFlagChange ", typeof handleFlagChange);

        if (componentIsMounted.current && typeof handleFlagChange != 'undefined' && typeof handleFlagChange != 'undefined') {
            console.log("foo ");
            var flag = rows.some(item => item.ClientDataVariableTypeName == null)
            handleFlagChange(flag)
        }
    }, []);

But that yields:

typeof handleFlagChange  undefined. <---In the Child
isFlagTrue  false <--- In Parent

Any ideas?

2
Try handleFlagChange !== undefined or !!handleFlagChange to check if handleFlagChange is defined or not, not typeof. - Lukas Bach
Change condition as if (componentIsMounted.current && handleFlagChange) - Rahul Kumar
@LukasBach Thanks for responding! That didn't work. - Antonio Pavicevac-Ortiz
@RahulKumar Thanks my friend, but that didn't work as well. - Antonio Pavicevac-Ortiz
I would recommend making an MVCE to narrow down the scope of the problem, and to ensure you're running the code you think you are. In the scenario provided I don't see any obvious way for handleFlagChange to be undefined. - Dave Newton

2 Answers

1
votes

Have you consider using a default value for the function and let the normal flow of React do yours?

function Child({handleFlagChange = () => {}})

Let me know if this works.

0
votes

I think this is a typescript error saying that the type of handleFlagChange is not known in child Component.

You have 2 option here:

First, declare type of each prop at first and then use it in function:

 type PropsType = { handleFlagChange: () => void }
    
 function Child({handleFlagChange}: PropsType)

Or try to add specific type in the function itself:

function Child({handleFlagChange: () => void})

where () => void being the type of handleFlagChange function.