Hi everyone!
I’ve recently written a blog post about building a decoupled event management service in React.
I've tried to explain the implementation of an Observer pattern using a custom Observer class, how to manage events efficiently with the Event Mediator Provider, and how to make your React components more modular and scalable.
I’d really appreciate hearing your thoughts and feedback, especially if you’ve implemented similar patterns or have suggestions for improvement!
Here is link.
Your default state for products is [], so the conditional render data.products in ProductDetail.js always return true so you can change default state for products is null
const [products, setProducts] = useState(null);
The first answer is correct, so I will not duplicate it, but I see room for improvement in your code/example.
Your useGetProducts hook is very easy to break and hard to reuse. If you will pass the wrong URL or the structure of the API will change it will break your code. Also, the hook is not very generic, cause you will need to create similar fn for each entity. My suggestion. Use react-query and separate functions for calling API. So it will look like this.
import { useQuery } from 'react-query'
import axios from 'axios'
export default function ProductPage() {
const productResponse = useQuery('exchanges', () => getProduct('6'))
const { isLoading, isError, data: product } = productResponse
return (
<div>
{isLoading && <div>Loading...</div>}
{isError && <div>Something went wrong :(</div>}
{product && (
<div>
<h1>Product title: {product.title}</h1>
<p>
{product.images.map(imageSrc => (
<img key={imageSrc} src={imageSrc} alt="" />
))}
</p>
</div>
)}
</div>
)
}
interface Product {
id: string
title: string
images: string[]
}
function getProduct(id: string): Promise<Product> {
return axios
.get(`https://api.escuelajs.co/api/v1/products/${id}`)
.then(r => r.data)
}
PS. react-query requires additional configuration ( context provider, config, etc ). Please look into docs on how to use it.
Don't use
refwhen you use the option api, you're mixin up option api and composition api (thesetupfunction)Move your api call to a method and call it from both
createdandhandleClick
export default {
components: {
Clothes,
Shoes,
},
data() {
return {
product: 1,
stores: [],
errors: [],
};
},
methods: {
fetchProduct(productId) {
return axios.get(`https://api.escuelajs.co/api/v1/categories/${productId}/products`)
.then((res) => {
this.stores = res.data;
})
.catch((e) => {
this.errors.push(e);
console.error(e);
});
},
handleClick(productId) {
this.product = productId;
this.fetchProduct(productId);
},
},
//Here is the Api call.
async created() {
await this.fetchProduct(this.product);
},
};
You need to wait for sync call :
const app = Vue.createApp({
data() {
return {
product: 1,
stores: [],
errors: [],
};
},
methods: {
async fetchProduct(productId) {
await axios.get(`https://api.escuelajs.co/api/v1/categories/${productId}/products`)
.then((res) => {
this.stores = res.data;
})
.catch((e) => {
this.errors.push(e);
console.error(e);
});
},
handleClick(productId) {
this.product = productId;
this.fetchProduct(productId);
},
},
async created() {
await this.fetchProduct(this.product);
},
})
app.mount('#demo')
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.2.2/axios.min.js" integrity="sha512-QTnb9BQkG4fBYIt9JGvYmxPpd6TBeKp6lsUrtiVQsrJ9sb33Bn9s0wMQO9qVBFbPX3xHRAsBHvXlcsrnJjExjg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div id="demo">
<button @click="handleClick(3)">get productid 3</button>
{{stores}}
</div>