When I am fetching the data from API, If I get Ok I will render the component to display the data, If an error has occured, I want to display a custom message for different components, and during fetching the data I want to show a loading message.
export default function App() {
const { data: products, loading, error } = useFetch(
"products?category=shoes"
);
if (error) return <div>Failed to load</div>;
if (loading) return <div>wait is Loading</div>;
return (
<>
<div className="content">
<section id="products">{products.map((product) =>{return <div>product.name</div>})}</section>
</div>
</>
);
}
I am planning to have a fetch call in multiple components. So, I was thinking If I could write the above logic in one place, like an HOC or Rendered Props and reuse it.
What I tried: but failed HOC wont work because you cant call hooks in normal functions. It has to be a Component. Rendered Props wont work as it gives this error: Error: Rendered more hooks than during the previous render.
Below is my failed rendered props code
const ShowData= function ({ data: products }) {
return (
<div>
{products.map(product => {return <div>product.name</div>})}
</div>
);
};
function SearchCount({ count }) {
return <h3>Search Results: {count} items found</h3>;
}
const Wrapper = function () {
return (
<LoadingAndError
render={ShowData}
params={{ url: "products?category=shoes" }}
></LoadingAndError>
);
};
export default Wrapper;
Loading and error logic is moved to the LoadingAndError component
const LoadingAndError = function (props) {
const { url } = props.params;
const { data: products, loading,error} = useFetch(url);
if (loading)
return <h1>Loading</h1>;
if (error) return <h1>Error</h1>;
return props.render({ data: products });
};
CodePudding user response:
return props.render({ data: products });
This line is calling props.render
as a function, but you've passed in a component. Calling component directly can cause exactly the error you're seeing. If you want props.render
to be used like this, then you should pass in a function which creates an element, like this:
<LoadingAndError
render={(props) => <ShowData {...props} />}
params={{ url: "products?category=shoes" }}
></LoadingAndError>
Alternatively, if you want to keep passing in render={ShowData}
, then change loadingAndError to create an element:
const loadingAndError = function (props) {
const { url } = props.params;
const { data: products, loading,error} = useFetch(url);
if (loading)
return <h1>Loading</h1>;
if (error) return <h1>Error</h1>;
const Component = props.render
return <Component data={products}/>
}