在 redux 操作中查询 api 时的无限循环

mlz*_*lz7 8 javascript firebase reactjs redux react-redux

我正在尝试通过 redux-thunk 操作查询我的 Firebase 后端,但是,当我在使用 的初始渲染中这样做时useEffect(),我最终遇到此错误:

Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
Run Code Online (Sandbox Code Playgroud)

我的操作只是返回一个 Firebase 查询快照,然后我在我的减速器中收到了它。我使用钩子来调度我的动作:

export const useAnswersState = () => {
    return {
        answers: useSelector(state => selectAnswers(state)),
        isAnswersLoading: useSelector(state => selectAnswersLoading(state))
    }
}

export const useAnswersDispatch = () => {
    const dispatch = useDispatch()
    return {
        // getAnswersData is a redux-thunk action that returns a firebase snapshot
        setAnswers: questionID => dispatch(getAnswersData(questionID))
    }
}
Run Code Online (Sandbox Code Playgroud)

和以下选择器从我的快照和 redux 状态中获取我需要的数据:

export const selectAnswers = state => {
    const { snapshot } = state.root.answers
    if (snapshot === null) return []
    let answers = []
    snapshot.docs.map(doc => {
        answers.push(doc.data())
    })
    return answers
}

export const selectAnswersLoading = state => {
    return state.root.answers.queryLoading || state.root.answers.snapshot === null
}
Run Code Online (Sandbox Code Playgroud)

在我的实际组件中,我尝试首先通过调度我的操作来查询我的后端,然后在数据加载后尝试读取结果数据,如下所示:

const params = useParams() // params.id is just an ID string

const { setAnswers, isAnswersLoading } = useAnswersDispatch()
const { answers } = useAnswersState()

useEffect(() => {
    setAnswers(params.id)
}, [])

if (!isAnswersLoading)) console.log(answers)
Run Code Online (Sandbox Code Playgroud)

所以为了澄清,我正在使用 myuseAnswersDispatch来调度一个 redux-thunk 操作,该操作返回一个 firebase 数据快照。然后我使用我的useAnswersState钩子在加载数据后访问它。我试图在useEffect我的实际视图组件中调度我的查询,然后使用我的状态钩子显示数据。

但是,当我尝试打印 的值时answers,我从上面收到错误。我将不胜感激任何帮助,如果这有帮助,我很乐意提供更多信息,但是,我已经测试了我的减速器和操作本身,它们都按预期工作,所以我相信问题出在文件中如上所述。

lau*_*nat -1

尝试重构您的动作创建器,以便dispatch在效果中调用它。您需要根据效果触发来进行调度。

查看相关

const setAnswers = (params.id) => {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(useAnswersDispatch(params.id));
  }, [])
}

Run Code Online (Sandbox Code Playgroud)

假设getAnswersData是一个选择器,效果将触发分派到您的应用程序状态,当您收到响应时,您的选择器getAnswersData将选择您想要的字段。

我不确定params.id它来自哪里,但您的组件依赖它来确定应用程序状态的答案。

触发调度后,仅更新应用程序状态,而不更新组件状态。使用 设置变量useDispatch,您可以在组件的生命周期中获得对 redux 存储的调度函数的变量引用。

要回答您的问题,如果您希望它处理多个调度,请将params.id和添加dispatch到效果中的依赖项数组中。

// Handle null or undefined param.id
const answers = (param.id) => getAnswersData(param.id);
const dispatch = useDispatch();
useEffect(() => {
     if(params.id) 
        dispatch(useAnswersDispatch(params.id));
  }, [params.id, dispatch]);

console.log(answers);
Run Code Online (Sandbox Code Playgroud)