多次调用 UseEffect 导致问题

时间:2021-03-03 04:54:26

标签: reactjs use-effect

有人可以解释为什么多次调用 useEffect 钩子(如下面的代码)会导致陈旧状态?

imports ...

function App () {
  const classes = useStyles()
  const [formState, setFormState] = useState({
    ageLevel: '',
    schoolGrade: '',
    booksCategories: '',
    numTitle: '',
    titleTypes: '',
    materialType: '',
    subjInterest: '',
    pastBook: '',
    numOfBags: '',
    bag1: '',
    bag2: '',
  })

  const handleTxtFldChange = (e, name) => {
    setFormState({ ...formState, [name]: e.target.value })
  }
  useEffect(() => {
    if (formState.ageLevel !== 'Adults') {
      setFormState({
        ...formState,
        numTitle: '',
        materialType: '',
        subjInterest: '',
        pastBook: ''

      })
    }
  }, [formState.ageLevel])

  useEffect(() => {
    if (formState.ageLevel !== 'Toddlers' || formState.ageLevel !== 'Preschoolers') {
      setFormState({
        ...formState,
        numOfBags: '',
        bag1: '',
        bag2: ''
      })
    }
  }, [formState.ageLevel])

  useEffect(() => {
    if (formState.ageLevel !== 'School-Age') {
      setFormState({
        ...formState,
        schoolGrade: '',
        booksCategories: ''
      })
    }
  }, [formState.ageLevel])

  useEffect(() => {
    if (formState.ageLevel !== 'Teens') {
      setFormState({
        ...formState,
        titleTypes: '',
        subjInterest: '',
        pastBook: ''
      })
    }
  }, [formState.ageLevel])
  return (
    <>
      <div className='App'>
        <Container>
            <AgeLevelSelect
              formState={formState}
              setFormState={setFormState}
            />
            <GradeSelect
              formState={formState}
              setFormState={setFormState}
            />
            <BooksCategories
              formState={formState}
              setFormState={setFormState}
            />
            <NumTitles
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
            />
            <TypeOfTitles
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
              location={formState.location}
            />
            <TypeOfMaterial
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
            />
            <SubjOfInterest
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
              materialType={formState.materialType}
            />
            <PastBook
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
              materialType={formState.materialType}

            />
            <NumOfBag
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
            />
            <Bag1
              formState={formState}
              setFormState={setFormState}
              numOfBags={formState.numBookBags}
            />
            <Bag2
              formState={formState}
              setFormState={setFormState}
              numOfBags={formState.numBookBags}
            />
          </form>
        </Container>
      </div>
    </>
  )
}

export default App

任何想法,我做错了什么?
我想要实现的只是在用户切换表单中的关闭和打开问题时重置部分状态,但显然,我缺少一些基本的反应概念。

1 个答案:

答案 0 :(得分:1)

这是因为 formState 未包含在 useEffect 的依赖项数组中,而是用于 useEffect 中。

但是,如果您将其添加到 useEffect 的依赖项数组中,您将收到一个无限循环。

为了解决这个问题,你可以使用 setState 的回调语法,不要求它在依赖数组中但仍然接收当前值。

function App () {
  const classes = useStyles()
  const [formState, setFormState] = useState({
    ageLevel: '',
    schoolGrade: '',
    booksCategories: '',
    numTitle: '',
    titleTypes: '',
    materialType: '',
    subjInterest: '',
    pastBook: '',
    numOfBags: '',
    bag1: '',
    bag2: '',
  })

  const handleTxtFldChange = (e, name) => {
    setFormState({ ...formState, [name]: e.target.value })
  }

  useEffect(() => {
    setFormState(currentState => {
        const newState = { ...currentState };

        if (formState.ageLevel !== 'Adults') {
            newState.numTitle = '';
            newState.materialType = '';
            newState.subjInterest = '';
            newState.pastBook = ''
        }

        if (formState.ageLevel !== 'Toddlers' && formState.ageLevel !== 'Preschoolers') {
            newState.numOfBags = '';
            newState.bag1 = '';
            newState.bag2 = '';
        }

        if (formState.ageLevel !== 'Teens') {
            newState.titleTypes = '';
            newState.subjInterest = '';
            newState.pastBook = '';
        }

        return newState;
    });
  }, [formState.ageLevel]);

  return (
    <>
      <div className='App'>
        <Container>
            <AgeLevelSelect
              formState={formState}
              setFormState={setFormState}
            />
            <GradeSelect
              formState={formState}
              setFormState={setFormState}
            />
            <BooksCategories
              formState={formState}
              setFormState={setFormState}
            />
            <NumTitles
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
            />
            <TypeOfTitles
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
              location={formState.location}
            />
            <TypeOfMaterial
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
            />
            <SubjOfInterest
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
              materialType={formState.materialType}
            />
            <PastBook
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
              materialType={formState.materialType}

            />
            <NumOfBag
              formState={formState}
              setFormState={setFormState}
              ageLevel={formState.ageLevel}
            />
            <Bag1
              formState={formState}
              setFormState={setFormState}
              numOfBags={formState.numBookBags}
            />
            <Bag2
              formState={formState}
              setFormState={setFormState}
              numOfBags={formState.numBookBags}
            />
          </form>
        </Container>
      </div>
    </>
  )
}

export default App

注意:我假设 if (formState.ageLevel !== 'Toddlers' || formState.ageLevel !== 'Preschoolers') 应该是 if (formState.ageLevel !== 'Toddlers' && formState.ageLevel !== 'Preschoolers') 否则它总是会评估为真。