<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jean Lambert</title>
    <description>The latest articles on DEV Community by Jean Lambert (@jeanlambert).</description>
    <link>https://dev.to/jeanlambert</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78948%2F2d621e49-797b-4d05-8658-4f4cf50cef1d.jpg</url>
      <title>DEV Community: Jean Lambert</title>
      <link>https://dev.to/jeanlambert</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeanlambert"/>
    <language>en</language>
    <item>
      <title>Create a custom HTTP hook with TypeScript</title>
      <dc:creator>Jean Lambert</dc:creator>
      <pubDate>Tue, 29 Sep 2020 17:01:11 +0000</pubDate>
      <link>https://dev.to/jeanlambert/create-a-custom-http-hook-with-typescript-4ok3</link>
      <guid>https://dev.to/jeanlambert/create-a-custom-http-hook-with-typescript-4ok3</guid>
      <description>&lt;p&gt;Hey, React community, in this article, you will find how to create a simple-to-use HTTP hook for making HTTP calls on your React or React Native app.&lt;/p&gt;

&lt;p&gt;First, let's create a simple hook&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function useHttp&amp;lt;T&amp;gt;() {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;T&lt;/strong&gt; is the type of data our hook and the HTTP response will return&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's add some parameters&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function useHttp&amp;lt;T&amp;gt;(
  request: HttpRequest&amp;lt;T&amp;gt;,
  cb?: HttpCallback&amp;lt;T&amp;gt;,
  config?: HttpConfig&amp;lt;T&amp;gt;,
): HttpHook&amp;lt;T&amp;gt; {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Request: &lt;code&gt;request: HttpRequest&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type HttpRequest&amp;lt;T&amp;gt; = (body?: any) =&amp;gt; Promise&amp;lt;T&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;HttpRequest&lt;/strong&gt; should be the actual API call our hook will execute. The &lt;strong&gt;body&lt;/strong&gt; object is the data you will pass every time you make a request.&lt;/p&gt;

&lt;p&gt;This could be simplified by passing an URL instead of a promise, but what if you want to call multiple APIs at the same time?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Callback:

&lt;code&gt;cb?: HttpCallback&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type HttpCallback&amp;lt;T&amp;gt; = (data: T, error?: HttpError) =&amp;gt; void
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A callback function that's going to be called every time the API call is resolved.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Config: &lt;code&gt;config?: HttpConfig&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type HttpConfig&amp;lt;T&amp;gt; = {
  headers: any,
  timeout: number
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you can add any custom configuration you want to your API call, or maybe something that alters the behavior of your hook.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Return type
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type HttpHook&amp;lt;T&amp;gt; = [(body?: any) =&amp;gt; Promise&amp;lt;void&amp;gt;, {
  loading: boolean, 
  data: T, 
  error: HttpError | null
}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our hook will return 2 values&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The actual HTTP request&lt;/li&gt;
&lt;li&gt;An object with the loading state, the error state, and the response data&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The error type could be whatever you API returns. E.g:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class HttpError {
  status: number
  message: string

  constructor(status: number, message: string) {
    this.status = status
    this.message = message
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's go with the actual logic of our hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create some states for our 
const [loading, setLoading] = useState&amp;lt;boolean&amp;gt;(false)
const [error, setError] = useState&amp;lt;HttpError | null&amp;gt;(null)

async function fetchApi(body?: any): Promise&amp;lt;void&amp;gt; {
  setLoading(true)
  let err = null
  let data: T = {} as T
  try {
    // Await for the request
    const response: any = await request(body)
    // This might vary based on your API
    if(response.data) {
      data = response.data;
    } else {
      data = response;
    }
  } catch (_err) {
    err = _err
  } finally {
    // Set loading to false and verify the response status, if there's an error or whatever you need
    setLoading(false)
    if (err) {
      if(cb) cb(data, err)
      setError(err)
    } else {
      setResponse(data)
      setError(null)
      if(cb) cb(data)
    }
  }
}

return [fetchApi, {loading, data: response, error}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the simplest logic for our hook, from this you can add your own configuration params, change the validation based on your API, you could also create a dataExtractor function if you need to use multiple APIs.&lt;/p&gt;

&lt;p&gt;Now! Let's go with some examples.&lt;/p&gt;

&lt;p&gt;First, create a data type and a dummy API call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type LightsaberType = {
  color: string,
  material: string
}

let lightsabers: LightsaberType[] = [{
  color: 'blue',
  material: 'Electrum Plated'
}, {
  color: 'red',
  material: 'Durasteel'
}]

const fetchLightsaberList = async () =&amp;gt; {
  return lightsabers
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it's as simple as this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const LightsaberListScreen = () =&amp;gt; {
  const [getLightsabers, { loading, data }] = useHttp&amp;lt;LightsaberType[]&amp;gt;(fetchLightsaberList)

  useEffect(() =&amp;gt; {
    getLightsabers()
  }, [])

  return (
    &amp;lt;View&amp;gt;
      {loading? (
        &amp;lt;ActivityIndicator /&amp;gt;
      ) : (
        &amp;lt;FlatList
          data={data || []}
          renderItem={({item}) =&amp;gt; null}
        /&amp;gt;
      )}
    &amp;lt;/View&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, what if you want to handle your own state...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const LightsaberListScreen = () =&amp;gt; {
  const [lightsabers, setLightsabers] = useState&amp;lt;LightsaberType[]&amp;gt;([])
  const [getLightsabers, { loading }] = useHttp&amp;lt;LightsaberType[]&amp;gt;(
    fetchLightsaberList,
    (data, err) =&amp;gt; {
      if(err) showCustomToast('Oh no, I don\'t have any lightsaber!')
      setLightsabers(data)
    }
  )

  useEffect(() =&amp;gt; {
    getLightsabers()
  }, [])

  return (
    &amp;lt;View&amp;gt;
      {loading? (
        &amp;lt;ActivityIndicator /&amp;gt;
      ) : (
        &amp;lt;FlatList
          data={lightsabers}
          renderItem={({item}) =&amp;gt; null}
        /&amp;gt;
      )}
    &amp;lt;/View&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OR you need to pass a body&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const postLightsaber = async (lightsaber: LightsaberType) =&amp;gt; {
  lightsabers.push(lightsaber)
  return lightsabers
}


...LightsaberListScreen component
const [createLightsaber] = useHttp&amp;lt;LightsaberType[]&amp;gt;(
    (body: LightsaberType) =&amp;gt; postLightsaber(body),
    (data, err) =&amp;gt; {
      if(err) showCustomToast('Oh no, you\'ll need to go back to Ilum')
      setLightsabers(data)
    }
  )

return (
  &amp;lt;Button 
    text="Create your own lightsaber"
    onPress={() =&amp;gt;  createLightsaber({
        color: 'cian',
        material:'Aurodium'
  })}/&amp;gt;
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is my first article so I really hope you like it and I'm completely open to suggestions!&lt;/p&gt;

&lt;p&gt;Happy coding 🚀&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
