1

I am having trouble accessing state after saving it, when calling the same function. My state is setup like this:

const perLanguageDefault = {
  calculated_skill: null,
  display_skill: null,
  published: false,
  premium: false,
  id: null,
};

  const [perLanguage, setPerLanguage] = useState(perLanguageDefault);

I have a save function inside one of my components as such:

  const _savePerLanguageArticle = async () => {
    if (perLanguage.id === null) {
      await _createPerLanguage();
    } else if (perLanguage.id !== null) {
      await _updatePerLanguage();
    }
    if (props.sentences.length !== 0 && perLanguage.id) {
      await _iterateSentences();
    }
    await _saveRulesArticle();
  };

If a perLanguage object doesn't exist, I create one in the database, and set it in state as such:

  const _createPerLanguage = async () => {
    const body = {
      published: perLanguage.published,
      premium: perLanguage.premium,
      article: props.article.id,
      language: props.lang_id,
      calculated_skill: perLanguage.calculated_skill,
      display_skill: perLanguage.display_skill,
    };
    try {
      const response = await api.post("perLanguageCreateAPI", {
        body: body,
      });
      await setPerLanguage(response.data);
    } catch (e) {
      console.log(e.response);
    }
  };

_saveRulesArticle above looks like this:

  const _saveRulesArticle = async () => {
    const newRules = props.rules.map((rule) => {
      let ruleobj = {};
      ruleobj["rule"] = rule;
      ruleobj["per_language"] = perLanguage.id;
      return ruleobj;
    });
    try {
      const response = await api.post("ruleMappingCreateAPI", {
        body: newRules,
      });
    } catch (e) {
      console.log(e.response);
      return;
    }
  };

However, because it's all within the same top function, _saveRulesArticle doesn't get access to the new perLanguage variable, it isn't updated, even though _createPerLanguage supposedly creates it and sets it.

I suspect there's some relation to this stack overflow page:

useState set method not reflecting change immediately

Most particularly the highest upvoted answer. I understand how that works for useEffect, but how would it work here? How do I update state inside a function, and then later inside that function, access the same updated state? Is this possible? Is this an anti-pattern?

Steven Matthews
  • 9,705
  • 45
  • 126
  • 232
  • why are you using await with setPerLanguage? Remove await in front of it and pass your data to setPerLanguage func. – Gulshan Aggarwal Jan 23 '22 at 17:11
  • 2
    `setState` can't be awaited, and the updated value will never be available until the next render cycle. You can either assign the new value to a variable, work with it and then call `setState` on all relevant state variables, or you can define a `useEffect` to be triggered on render to handle the updated value. – pilchard Jan 23 '22 at 17:34
  • 1
    It looks like you just need a single `useEffect` dependent on`perLanguage` which will call `iterateSentences` and `saveRulesArticle` each time a change is registered. – pilchard Jan 23 '22 at 17:51
  • @pilchard Possibly, though I also update perLanguage via an API call after setting defaults, so I have to think about the best way to structure that. I understand what I am doing wrong now, with your comment and applying it to the lesson from the other stack overflow post – Steven Matthews Jan 23 '22 at 17:53
  • 1
    That's great, sounds like you're on the right track. – pilchard Jan 23 '22 at 17:54

0 Answers0