【问题标题】:React Custom Hook function is not reading recoil AtomReact Custom Hook 函数未读取反冲原子
【发布时间】:2021-09-10 06:03:31
【问题描述】:

我正在尝试在 react 项目中使用 formik、typescript 和 recoil 制作一个多请求、多步骤的表单。我创建了一个自定义钩子,它返回三个函数,其中一个函数需要一个特定的 UUID 用于它正在使用的模型,以便它可以发出 PUT 请求。当我使用另一个相同的钩子函数发出 POST 请求时,这个 UUID 被设置为一个 Recoil Atom,然后我尝试在它下面的函数中访问它,但它没有正确显示。我试图等待它并将其分配给一个变量,但无济于事,当我在函数外部记录它时,状态返回我需要的值,但是当我将它记录在函数内部(我需要它的地方)时,它是空的。我正在尝试避免使用本地存储,因为这意味着要管理另一种类型的数据,这可能会破坏我的程序的其余部分。

这是钩子:

const useInstitution = () => {
  const setCurrentId = useSetRecoilState(institutionId);
  const currentId = useRecoilValue(institutionId);

  console.log(currentId);
  // The above line properly logs the UUID I want
  
  const handleValues = useCallback((values: InstitutionFormType) => {
    
    return {
      ...values,
      institution_registered_number: values.institution_registered_number.replace(/\D+/g, ''),
      institution_id: currentId || values.institution_id,
    };
  }, [currentId]);

  const insertInstitution = useCallback(async (values, callback) => {
    const newValues = handleValues(values);
    const {
      institution_logo_file,
    } = newValues;
    const response = await createInstitution(newValues);
    setCurrentId(response?.data.institution_id);
  }, [handleValues, setCurrentId]);

  const institutionEdit = useCallback(async (values, callback) => {
    const newValues = handleValues(values);
    console.log(currentId);
    // This line logs an empty value

  }, [currentId, handleValues]);

  return {
    insertInstitution, institutionEdit, currentId,
  };
};

export default useInstitution;

这是原子:

export const institutionId = atom({
  key: 'institutionId',
  default: '',
});

在这个钩子中,当 createInstitution 请求被调用并成功时,id 被设置为 Recoil Atom institutionId,我尝试将它记录在两个不同的行,一个在函数之外,一个在函数institutionEdit内,例如:

第一行是来自console.log的日志,在函数之外和钩子内部。第二行是机构编辑函数中的console.log。

为什么会这样?如何在钩子函数中正确访问它?

【问题讨论】:

    标签: reactjs state recoiljs


    【解决方案1】:

    useSetRecoilState 文档指出

    返回一个 setter 函数,可以异步使用它来改变状态。 setter 可以传递一个新值,也可以传递一个更新函数,该函数接收以前的值作为参数。

    状态由useSetRecoilState返回的setter异步改变。为了在更新的状态下执行某些操作,您应该使用useEffect 来监控更改并运行所需的代码。

    请参见下面的示例。

    const {
      useCallback,
      useEffect,
      useContext,
    } = React;
    const {
      RecoilRoot,
      atom,
      useSetRecoilState,
      useRecoilValue
    } = Recoil;
    
    const institutionId = atom({
      key: 'institutionId',
      default: '',
    });
    
    const createInstitution = () => new Promise(res => setTimeout(() => res({
      data: {
        institution_id: Math.round(Math.random() * 50)
      }
    }), 1500))
    
    const useInstitution = () => {
      const setCurrentId = useSetRecoilState(institutionId);
      const currentId = useRecoilValue(institutionId);
    
      console.log(currentId);
      // The above line properly logs the UUID I want
    
      const handleValues = useCallback((values: InstitutionFormType) => {
    
        return {
          ...values,
          institution_registered_number: values.institution_registered_number.replace(/\D+/g, ''),
          institution_id: currentId || values.institution_id,
        };
      }, [currentId]);
    
      const insertInstitution = useCallback((values, callback) => {
        const newValues = handleValues(values);
        const {
          institution_logo_file,
        } = newValues;
        createInstitution(newValues).then(response =>
          setCurrentId(response && response.data.institution_id));
      }, [handleValues, setCurrentId]);
    
      const institutionEdit = useCallback((values, callback) => {
        const newValues = handleValues(values);
        console.log(currentId);
        // This line logs an empty value
    
      }, [currentId, handleValues]);
    
      return {
        insertInstitution,
        institutionEdit,
        currentId,
      };
    };
    
    const insts = new Array(10).fill().map((v, i) => ({
      institution_logo_file: 'logo 1',
      institution_registered_number: `reg no ${i}`
    }))
    
    const App = () => {
        const {
          insertInstitution,
          institutionEdit,
          currentId,
        } = useInstitution();
    
        useEffect(() => {
          insertInstitution(insts[0])
        }, [])
    
        // Getting the recoil state value
        const recoilValue = useRecoilValue(institutionId)
        useEffect(() => {
          institutionEdit(insts[0])
        }, [institutionEdit, recoilValue]) // execute only when `recoilValue` changes
        console.log(recoilValue)
    
        return ( < div > Hi < /div>)
        }
    
        ReactDOM.render( < RecoilRoot > < App / > < /RecoilRoot> , document.querySelector('#root'))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/recoil@0.3.1/umd/recoil.min.js"></script>
    <div id="root" />

    【讨论】:

      猜你喜欢
      • 2020-08-23
      • 1970-01-01
      • 1970-01-01
      • 2020-11-18
      • 2021-09-08
      • 2020-11-20
      • 2020-12-09
      • 1970-01-01
      • 2021-09-20
      相关资源
      最近更新 更多