2

I have created a popup that the user can use to add stuff to the application, every field is a separate component, because I need to reuse them in several places in different configruations.

I have tried to create an innerRef that when changed (i.e. new value is typed), the useEffect of the component should be triggered to show or hide the Done button if all values are valid.

I know that all values are valid or not from the valid prop that I assign to .current

export default function AddStock() { const selectTypeOfQuantityRef = useRef({}); const [allValid, setAllValid] = useState(false); useEffect(() => { const allValues = [selectTypeOfQuantityRef.current.valid]; allValues.every((value) => value) ? setAllValid(true) : setAllValid(false); console.log(allValues.every((value) => value)); // does not get triggered }, [selectTypeOfQuantityRef.current]); return ( <> <AddPopup> <SelectTypeOfQuantity innerRef={selectTypeOfQuantityRef} /> {allValid && <DoneButton/>} <CancelButton/> </AddPopup> </> ); } 

And this is the select itself (custom of course), that sets innerRef, whenever its state changes. Everything here works, the state of this small component itself is managed correctly, but it just does not get triggered the state update of the parent component

export default function SelectTypeOfQuantity({ defaultValue = null, innerRef }) { const [selectTypeOfQuantity, setSelectTypeOfQuantity] = useState(defaultValue); const [valid, setValid] = useState(false); const [errMessage, setErrMessage] = useState("Избери стойност!"); useEffect(() => { innerRef.current.value = selectTypeOfQuantity; handleValidation(selectTypeOfQuantity); }, [selectTypeOfQuantity]); const handleValidation = (value) => { const result = validateAutocomplete(value); if (result.valid) { setValid(true); setErrMessage(null); innerRef.current.valid = result.valid; } else { setValid(false); setErrMessage(result.errMessage); } }; const selectTypeOfQuantityOnChange = (e, val) => { setSelectTypeOfQuantity(val ? val.value : null); }; return ( <Select onChange={selectTypeOfQuantityOnChange}/> ); } 
2
  • Try changing the const to: SelectTypeOfQuantityOnChange. Its case sensitive issue i guess here in the first look Commented Jan 29, 2021 at 8:15
  • @MithunShreevatsa good eye Mithun, but thats not the issue, I have just mistyped it whhen transfering the code here. The onChange of select works just fine. My whole popup works just fine (if i remove the allValid condition), its just that I cant show back the DoneButton Commented Jan 29, 2021 at 8:17

1 Answer 1

4

useRef does not trigger rerenders, thus useEffect will not be called

Use useRef when you need information that is available regardless of component lifecycle and whose changes should NOT trigger rerenders. Use useState for information whose changes should trigger rerenders.

Solution

As React's Philosophy states, all the data must reside within React, that's why even input components are supplied with a value and onChange event. React can't track data changes that happens outside it. As I understand from your question, the changes are happending within the React App, So instead of tracking the data through the innerRef, track them within React using React's own methods.

Sign up to request clarification or add additional context in comments.

3 Comments

useRef does not trigger rerenders, that is why I have placed it in the array of variables that useeffect should monitor.
Also refs cant be binded with components, you can include it with input elements or select elements, i see you have used for Custom component here. It should be vice versa. Custom component will not consist of attributes like current.value as its input attributes. It is better you trigger a function rather than binding it to ref i feel or as mentioned state change
I ended up making a new state variable in AddStock and a custom onChange function, I was trying to avoid that, because I thought that it will add too much additional code in AddStock (what I was trying to avoid in the first place, because I have many more fields), but it turned out much better than I expected.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.