0

I need to update my state after updating / setting a different state in my useEffect hook. So far it does not work. What am I doing wrong here?

The isDisabled logic depends on the values of the other states.

const OffersDialogueButton = ({
  type,
  status,
}) => {
  const { invitationType, status: cardStatus } = useJobPositionsContext();
  const { jobPosition } = useJobDetailContext();
  const [dialogStatus, setDialogStatus] = useState<CardStatus>();
  const [dialogType, setDialogType] = useState<CardType>();
  const [color, setColor] = useState<string>();
  const [isDisabled, setIsDisabled] = useState(false);

  useEffect(() => {
    setDialogStatus(status || cardStatus);
    setDialogType(type || invitationType || 'default');
    setIsDisabled(
      (dialogType === 'invitation' && dialogStatus !== 'pending') || (dialogType === 'application' && cardStatus !== 'accepted'),
    );
    setColor(BUTTON_VARIANT_BY_STATUS[dialogStatus]);
  }, [type, status, isDisabled]);
jondiur
  • 3
  • 3
  • You are not watching for dialogType or dialogStatus changes, add them to the dependency array and it should fix it. – Ian Craddock May 23 '22 at 08:10

3 Answers3

1

dialogType and dialogStatus are set in the same function with state set which is async so you cannot expect them to be set when you check them in the same function. You should have a new useEffect for those variables or have a local variable for the checks.

grekier
  • 2,322
  • 1
  • 16
  • 23
1

As I understand you want to make setIsDisabled by setDialogType , you need to use other useEffect

React.useEffect(() => {
    setIsDisabled(
      (dialogType === 'invitation' && dialogStatus !== 'pending') || (dialogType === 'application' && cardStatus !== 'accepted'),
    );
  }, [dialogType])

setDialogType is asynchronous , you can not access it immediately after the setState.

Read more about React state here State

Hakob Sargsyan
  • 1,294
  • 1
  • 9
  • 15
0

When computing isDisabled and color state variables, you must use the new values of dialogStatus and dialogType.

const OffersDialogueButton = ({type, status}) => {
  const { invitationType, status: cardStatus } = useJobPositionsContext();
  const { jobPosition } = useJobDetailContext();
  const [dialogStatus, setDialogStatus] = useState<CardStatus>();
  const [dialogType, setDialogType] = useState<CardType>();
  const [color, setColor] = useState<string>();
  const [isDisabled, setIsDisabled] = useState(false);

  useEffect(() => {
    const nextDialogStatus = status || cardStatus;
    const nextDialogType = type || invitationType || 'default';
    const nextIsDisabled = 
      (nextDialogType === 'invitation' && nextDialogStatus !== 'pending') || 
      (nextDialogType === 'application' && cardStatus !== 'accepted');
    const nextColor = BUTTON_VARIANT_BY_STATUS[nextDialogStatus];

    setDialogStatus(nextDialogStatus);
    setDialogType(nextDialogType);
    setIsDisabled(nextIsDisabled);
    setColor(nextColor);
  }, [status, cardStatus, type, invitationType]);
Olivier Boissé
  • 15,834
  • 6
  • 38
  • 56
  • Would I need to update my dependency array aswell? – jondiur May 23 '22 at 08:34
  • yes, I updated it in my answer – Olivier Boissé May 23 '22 at 09:28
  • So I do not need to put `isDisabled` and `setIsDisabled` in the dependency array? – jondiur May 23 '22 at 09:52
  • I have one small issue which is why I am asking, like I pick a different classname wether isDisabled is true or not, on initial render the className shows properly but after loading completely (rendering) the classname is wrong. Not sure if that is a different issue or if it is regarding the useEffect update. Before my changes the classname worked properly – jondiur May 23 '22 at 09:58
  • where do you compute the className ? It should work if you compute it when rendering the elements. If the calssName is wrong, it's maybe due to a mistake when computing the next `isDisabled` value in the `useEffect` – Olivier Boissé May 23 '22 at 10:22