You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在useEffect中使用Formik的setFieldValue避免无限循环

修复Formik与useEffect的无限循环问题

核心原因

每次组件重新渲染时,useFormik返回的formik对象都是全新的引用。如果将整个formik对象加入useEffect依赖项,会导致useEffect在每次渲染时都触发,进而调用setFieldValue引发组件重新渲染,形成无限循环。

解决方案

方案1:仅依赖formik.setFieldValue而非整个formik对象

useFormik返回的setFieldValue是稳定引用,不会随组件渲染而变化。修改依赖项,只传入这个方法即可避免循环:

import {
  useGetMemberFunctionalityWithLimitMutation,
} from '../../../../redux/services/employeeManagement/employeeManagementApi';
import { useFormik } from 'formik';
import { useState, useEffect } from 'react';

function A1_EmployeeList() {
  const [getMemberFunctionalityWithLimit] = useGetMemberFunctionalityWithLimitMutation();
  const [paginationObj, setPaginationObj] = useState({
    page: 1,
    pageSize: 10,
    employeeListQuery: {
      employerUuid,
      fullnameOrId: '',
      payrollGroupUuid: '',
      schemeUuid: '',
    },
  });

  const searchFormSubmit = (values) => {
    const { fullnameOrId, payrollGroupUuid, schemeUuid } = values;
    const employeeListQuery = {
      ...paginationObj.employeeListQuery,
      fullnameOrId: fullnameOrId || '',
      payrollGroupUuid: payrollGroupUuid || '',
      schemeUuid: schemeUuid || '',
    };
    setPaginationObj({
      ...paginationObj,
      page: 1,
      employeeListQuery,
    });
  };

  const formik = useFormik({
    initialValues: {
      fullnameOrId: '',
      schemeUuid: '',
      payrollGroupUuid: '',
      dataList: [],
    },
    onSubmit: (values) => {
      searchFormSubmit(values);
    },
  });

  // 提取稳定的setFieldValue方法
  const { setFieldValue } = formik;

  useEffect(() => {
    const { employeeListQuery, pageSize, page } = paginationObj;
    getMemberFunctionalityWithLimit({
      page,
      limit: pageSize,
      employeeListQuery,
    })
      .unwrap()
      .then(({ payload }) => {
        setFieldValue('dataList', payload.employeeList);
      })
      .catch((error) => {
        console.log(error);
      });
  }, [setFieldValue, getMemberFunctionalityWithLimit, paginationObj]);

  return (
    // 组件JSX内容
  );
}

方案2:使用useFormikContext钩子(适合嵌套组件场景)

如果你的useEffect写在Formik表单的嵌套组件中,可以用useFormikContext获取setFieldValue,同样只依赖该方法:

import { useFormikContext } from 'formik';

// 组件内部
const { setFieldValue } = useFormikContext();

useEffect(() => {
  const { employeeListQuery, pageSize, page } = paginationObj;
  getMemberFunctionalityWithLimit({
    page,
    limit: pageSize,
    employeeListQuery,
  })
    .unwrap()
    .then(({ payload }) => {
      setFieldValue('dataList', payload.employeeList);
    })
    .catch((error) => {
      console.log(error);
    });
}, [setFieldValue, getMemberFunctionalityWithLimit, paginationObj]);

方案3:用useCallback包裹API回调(可选)

如果需要进一步保证回调逻辑的稳定性,可以用useCallback包裹API调用逻辑:

import { useState, useEffect, useCallback } from 'react';

// 组件内部
const fetchEmployeeData = useCallback(async () => {
  const { employeeListQuery, pageSize, page } = paginationObj;
  try {
    const { payload } = await getMemberFunctionalityWithLimit({
      page,
      limit: pageSize,
      employeeListQuery,
    }).unwrap();
    formik.setFieldValue('dataList', payload.employeeList);
  } catch (error) {
    console.log(error);
  }
}, [formik.setFieldValue, getMemberFunctionalityWithLimit, paginationObj]);

useEffect(() => {
  fetchEmployeeData();
}, [fetchEmployeeData]);

额外提示

原代码中searchFormSubmit里的payrollGroupUuid赋值逻辑疑似笔误(用schemeUuid作为判断条件),建议检查是否应为payrollGroupUuid: payrollGroupUuid || ''。

内容的提问来源于stack exchange,提问作者blizzard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 01:27:41