guanacone / fullstack_app

BSD Zero Clause License
0 stars 0 forks source link

API communication #20

Closed guanacone closed 4 years ago

guanacone commented 4 years ago

While trying to modify my useAPI hook I discovered I can't use hooks in event handlers... I really dont like the fact that I have a useAPI hook to fetch data and a submitToApi() function in UserNew, UserEdit and UserDestroy. What approach do you recommend?

edwmurph commented 4 years ago

oh right event handlers are special and i believe need to be synchronous idempotent functions or else i think it messes with the render loop

could you send me the snippet of what you tried?

untested but i feel like something along these lines should work:

const component = () => {
  const { trigger, result } = useAPI({ url, method, body })

  if ( result ) {
    return result;
  }

  return (<button onClick={trigger}>click me</button>);
};
guanacone commented 4 years ago

I did just modify the useAPI hook to take more arguments in:

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

const useAPI = ({ method, url, data }) => {
  const [content, setcontent] = useState(null);

  useEffect(() => {
    (async () => {
      const result = await axios({
        method,
        url,
        data,
      });
      setcontent(result.data);
    })();
  }, []);

  return content;
};

export default useAPI;

and inserted it in a handleSubmit()

import React from 'react';
import UserForm from './UserForm';
import useInput from '../hooks/useInput';
import useAPI from '../hooks/useAPI';
import url from '../url';

const handleSubmit = (evt, value1, value2) => {
  evt.preventDefault();
  useAPI({ method: 'post', url: `${url}/user`, data: { firstName: value1, familyName: value2 } });
};

const UserNew = () => {
  const firstName = useInput('');
  const familyName = useInput('');

  return (
    <UserForm
    handleSubmit = {(evt) => handleSubmit(evt, firstName, familyName)}
    firstName={firstName}
    familyName={familyName} />
  );
};

export default UserNew;

But this raises an error Error: Invalid hook call...

guanacone commented 4 years ago

oh right event handlers are special and i believe need to be synchronous idempotent functions or else i think it messes with the render loop

could you send me the snippet of what you tried?

untested but i feel like something along these lines should work:

const component = () => {
  const { trigger, result } = useAPI({ url, method, body })

  if ( result ) {
    return result;
  }

  return (<button onClick={trigger}>click me</button>);
};

That would be a separate component to be inserted where ever I need a button that submits to the API?

edwmurph commented 4 years ago

That was just an example of how the updated useAPI hook could be used in a component that triggers it by an event handler

I don't think you need a new component for this I was just showing what the updated useAPI could look like in one of your existing components

guanacone commented 4 years ago

And where exactelly would that go in handleSubmit()?

edwmurph commented 4 years ago

sorry i think after thinking about this a bit more i'd recommend just continuing using both useAPI and handleSubmit

useAPI is a hook which should be used when you want to abstract logic that depends on state + other React features. e.g. when you want to fetch data immediately when a component is mounted and then dynamically render the data after it's fetched.

for the use case of triggering an api call from a button click, it makes the most sense to just make that api request directly without of using any special React features

i agree it's not ideal to have both useAPI and handleSubmit, but one thing that might help is if you pull out the handleSubmit button into a shared location so it doesn't have to be redefined in each file

guanacone commented 4 years ago

Will rename the useAPI hook to useAPIget and define a handleSubmit() in /src/utils.