The component renders a dynamic block by asking the server, which means the editor preview is a network round trip for every attribute change.
import ServerSideRender from '@wordpress/server-side-render'
import { useDebounce } from '@wordpress/compose'
const debounced = useDebounce(attributes, 500)
<ServerSideRender
block="turkerdev/recent-products"
attributes={debounced}
/>
Without debouncing, typing a title fires a request per character and the editor becomes unusable on a slow connection. The alternative is writing the preview in JavaScript and the markup in PHP, which is two implementations of the same thing — so the trade is a duplicated renderer against a debounced request, and for a widget-sized block the request wins.