You will want to bind to the change event of your search field and sort field or watch v-models to update a query string and reload the page. Yes I know you want it to not refresh, but that is what Inertia is designed to do. You're still going to have to make a request to the backend for the data.
So the key is to use the router.get method, where you can put the currrent url, with the query string as the data, and set the preserveState and preserveScroll to true in the options. These two options will help make things look like the page is dynamically updating. To be efficient you should be using partial reloads - set an only attribute in the options as well. (https://inertiajs.com/partial-reloads).
In the example below, I'm only doing the search field and assuming your data is coming from a products attribute in the backend. I use the debounce method on lodash to debounce keyboard input.
<input type="search" v-model="searchField" >
const searchField = ref(''); //Should really load it from the query string
const url = route('products.index');
watch(searchField, debounce(() => {
router.get(url, {searchField: searchField.value}, {preserveState: true, preserveScroll: true, only: ['products']}
}, 300));
In practice I put this inside a reactive composable so I can apply it to multiple tables.