如何更新一个会影响进程React中另一个状态的状态

问题描述 投票:0回答:1

我试图更新

inferredFacts
状态,但在这个过程中它必须先更新
facts
状态,然后获取
facts
状态的更新值然后处理
inferredFacts
,问题是
inferredFacts
赢了无法获取
facts

的更新值

我尝试过使用 useEffect 和 useMemo,但它只是给了我无限循环,尽管我不确定我是否正确实现了它。

顺便说一句,我正在研究前向链接

export default function useFacts(answers: boolean[]) {
  const [facts, setFacts] = useState<Set<string>>(new Set([]));
  const [inferredFacts, setInferredFacts] = useState<Set<string>>(new Set([]));

  const addFact = useCallback((newFact: string) => {
    setFacts((prevFacts) => new Set([...prevFacts, newFact]));
  }, []);

  function populateFacts() {
    const tmpFacts = new Set<string>([]);
    if (answers[0]) {
      tmpFacts.add("a");
    }
    if (answers[1]) {
      tmpFacts.add("b");
    }
    if (answers[2]) {
      tmpFacts.add("c");
    }
    if (answers[3]) {
      tmpFacts.add("f");
    }

    setFacts(tmpFacts);
  }

  const factsHasAll = useCallback(
    // list = antecedent
    (list: string[]) => {
      const filteredFacts = list.filter((item) => facts.has(item));

      if (filteredFacts.length === list.length) {
        return true;
      }
      return false;
    },
    [facts]
  );

  const doForwardChaining = useCallback(
    (rules: Rule[]) => {
      const inferredFacts = new Set<string>([]);

      while (true) {
        let inferred = false;
        for (const rule of rules) {
          if (
            factsHasAll(rule.antecedent) &&
            !inferredFacts.has(rule.consequent)
          ) {
            addFact(rule.consequent);
            inferredFacts.add(rule.consequent);
            inferred = true;
            break;
          }
        }
        if (!inferred) break;
      }

      setInferredFacts((prev) => new Set([...prev, ...inferredFacts]));
    },
    [addFact, factsHasAll]
  );

  return {
    facts,
    populateFacts,
    doForwardChaining,
    inferredFacts,
  };
}

reactjs react-hooks react-state-management
1个回答
0
投票

您正在更新状态,这是一个异步操作,然后同步检查状态是否发生变化。

相反,您必须获取当前状态,创建

tempFacts
Set
,同步更新和检查它,完成后更新状态。

const answersToFact = ['a', 'b', 'c', 'f'] as const;

// list = antecedent
const factsHasAll = (list: string[], facts: Set<string>) => list.every(item => facts.has(item));

export default function useFacts(answers: boolean[]) {
  const [facts, setFacts] = useState<Set<string>>(new Set([]));
  const [inferredFacts, setInferredFacts] = useState<Set<string>>(new Set([]));

  function populateFacts() {
    setFacts(answersToFacts.reduce((set, fact, idx) => {
      if(answer[idx]).add(fact);
      
      return set;
    }, new Set<string>()));
  }

  const doForwardChaining = useCallback(
    (rules: Rule[]) => {
      const inferredFacts = new Set<string>([]);
      const tempFacts = new Set(facts);

      while (true) {
        let inferred = false;
        for (const rule of rules) {
          if (
            factsHasAll(rule.antecedent, tempFacts) &&
            !inferredFacts.has(rule.consequent)
          ) {
            tempFacts.add(rule.consequent);
            inferredFacts.add(rule.consequent);
            inferred = true;
            break;
          }
        }
        if (!inferred) break;
      }

      setFacts(facts);
      setInferredFacts((prev) => new Set([...prev, ...inferredFacts]));
    },
    [facts]
  );

  return {
    facts,
    populateFacts,
    doForwardChaining,
    inferredFacts,
  };
}
© www.soinside.com 2019 - 2024. All rights reserved.