Skip to content
Advertisement

Custom hook when taking data in next render lost data

I made a hook useSendFormData , when i use it i get Invalid hook call.

  • Hook takes

  • data from SubmitForm

  • url:string,

  • method: post or put

  • success: success message if it was success

  • id: not required but if item has id i is added to api call.

  • auth default false

Problem is it loses data on renders I don’t know how to describe it better so I made console.log ss

As you can see on second call I get data but later it’s gone…

problem image

My code for this custom hook:

    const sendFormData = async ({
    formData,
    url,
    method,
    success,
    id,
    auth = false,
  }) => {
    const setPartData = (partialData) => setData({ ...data, ...partialData });
    try {
      let response;
      if (method === "post") {
        response = await axios.post(
          `${SERVER_API}api/v1/${url}/${id ?? ""}`,
          formData
        );
      } else if (method === "put") {
        response = auth
          ? await fetchContext.authAxios.post(
              `${SERVER_API}api/v1/${url}/${id ?? ""}`,
              formData
            )
          : await axios.post(
              `${SERVER_API}api/v1/${url}/${id ?? ""}`,
              formData
            );
      }
      setPartData({
        data: response.data,
        loading: false,
        success,
        error: null,
      });
    } catch (err) {
      const { data } = err.response;
      setPartData({
        error: data.error,
        success: null,
        loading: false,
      });
    }
    return data;
  };

  return {
    sendFormData,
  };
};

And where is use it , it takes data from SubmitForm and make api call with it,as you can see in ss i get there undefined:

const { sendFormData } = useSendFormData()


const handleForm = async (info) => {
  // here you have your response.data returned
  const data = await sendFormData({
    formData: info,
    url: "auth/forgot-password",
    method: "post",
    success: "A password reset message has been sent to your email",
  });

  console.log(data);

  reset();
};

If you could help that would be awesome. If you have any optimatizaion hints for this hook please tell me.Thanks for your time.

Edit: Edit hook but doesnt return data value at the end

Advertisement

Answer

TL;DR

const setPartData = (partialData) => setData({ ...data, ...partialData });

should be changed to

const setPartData = (partialData) => setData(data => ({ ...data, ...partialData }));

Explanation

setState callback can take either the new state (what you have done), or another callback (what should be done). You should pass a callback like so, to make sure that multiple calls of setPartialData(someData) within sendFormData uses the latest data state to update itself (combining partialData). This approach is necessary as const sendFormData = () => {} is declared, the data variable used within is whatever data was outside the function block (from const [data, setData] = useState() ). This data is not updated as sendFormData() runs, instead only on the end of a component render cycle.

In other words,

const [data, setData] = useState(initialData);

const sendFormData = () => {
  const setPartData = (partialData) => setData({ ...data, ...partialData });
  setPartData(data1); // combines with initialData
  setPartData(data2); // combines with initialData as well
}

Note that where you declare const setPartData does not matter, as long as it has access to the data scope.

On the other hand,

const setPartData = (partialData) => setData(data => ({ ...data, ...partialData }));

uses the latest data state when setData() needs to run, by accessing it through the internal callback.

Since the hook you built can return the data state, once it is updated correctly, you can now use it like this in a better manner.

// App.js
const {data, sendFormData} = useSendFormData();

const sendAction = async (arg) => await sendFormData(arg);

return <>
  <button onClick={sendAction}>send data</button>
  { data.success || someCondition ? data : null }
</>

It’s probably not a good idea to reinvent the wheel when this swr library exists, but I commend your effort in trying to make code DRY.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement