DEV Community

Discussion on: React: "I really wish this is how I could write components."

Collapse
 
ericwooley profile image
Eric Wooley • Edited

Glorious! I love the idea.

I'm not a super big fan of hooks, I still prefer HOC, so for those who are interested, here is a similar alternative I am testing out.

Alternatively, a HOC would work just as well, and be decoupled.

// untested
import { ComponentType, useEffect, useState } from 'react'
import defaultPending from './defaultPending'
import defaultError from './defaultError'
import curry from 'lodash/curry'

interface IWithDataOptions<T> {
    pending?: () => ComponentType,
    error?: (e: Error) => ComponentType,
    data: (d: T) => componentType
}
export const withData = curry(<T> (
    url: string,
    options: IWithDataOptions<T> | ComponentType
) => {
    const error = options.error || defaultError
    const pending = options.pending || defaultPending
    const dataRender = options.data || options
    const WithData = (props) => {
        const [data, setData] = useState({ pending: true });

        useEffect(() => {
            fetch(url)
                .then(response => response.json())
                .then(data => setData({ data, pending: false }))
                .catch(error => setData({ error, pending: false }));
        }, [url]);
        if(data.pending) return pending()
        if(data.error) return error(data.error)
        return dataRender(data.data)
    }
    return WithData
});

// example 1
const Example = withData("https://swapi.co/api/people/1/?format=json", {
    pending: () => <div>Loading</div>,
    error: err => <div>{err.toString()}</div>,
    data: data => <pre>{JSON.stringify(data, null, 2)}</pre>
  }
);
<Example />

// example 2
const Example = withData("https://swapi.co/api/people/1/?format=json", (data) => <pre>{JSON.stringify(data, null, 2)}</pre>);
<Example />

// example 3
const withExampleData = withData("https://swapi.co/api/people/1/?format=json")
const Example =  withExampleData((data) => <pre>{JSON.stringify(data, null, 2)}</pre>)
<Example />

const CustomLoaderExample = withExampleData({
    peding: () => <div>Just a second...</div>,
    data: (data) => <pre>{JSON.stringify(data, null, 2)}</pre>
})

<CustomLoaderExample />

Collapse
 
joelnet profile image
JavaScript Joel

HOCs are another great way to solve this. Great examples!