diff --git a/examples/demo/src/orders/Basket.js b/examples/demo/src/orders/Basket.js
index 56b0ade3fa3..bb07917c45b 100644
--- a/examples/demo/src/orders/Basket.js
+++ b/examples/demo/src/orders/Basket.js
@@ -1,5 +1,4 @@
-import React, { useEffect } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
+import React from 'react';
 import classnames from 'classnames';
 
 import Table from '@material-ui/core/Table';
@@ -8,7 +7,7 @@ import TableCell from '@material-ui/core/TableCell';
 import TableHead from '@material-ui/core/TableHead';
 import TableRow from '@material-ui/core/TableRow';
 import Paper from '@material-ui/core/Paper';
-import { Link, useTranslate, crudGetMany } from 'react-admin';
+import { Link, useTranslate, useQueryWithStore, GET_MANY } from 'react-admin';
 import { makeStyles } from '@material-ui/core/styles';
 
 const useStyles = makeStyles({
@@ -20,26 +19,33 @@ const useStyles = makeStyles({
 const Basket = ({ record }) => {
     const classes = useStyles();
     const translate = useTranslate();
-    const dispatch = useDispatch();
-    const admin = useSelector(state => state.admin);
-
-    useEffect(() => {
-        const { basket } = record;
-        dispatch(crudGetMany('products', basket.map(item => item.product_id)));
-    }, [dispatch, record]);
-
-    if (!record) return null;
 
     const { basket } = record;
 
-    const productIds = basket.map(item => item.product_id);
-    const products = productIds
-        .map(productId => admin.resources.products.data[productId])
-        .filter(r => typeof r !== 'undefined')
-        .reduce((prev, next) => {
-            prev[next.id] = next;
-            return prev;
-        }, {});
+    const { loaded, data: products } = useQueryWithStore(
+        {
+            type: GET_MANY,
+            resource: 'products',
+            payload: {
+                ids: basket.map(item => item.product_id),
+            },
+        },
+        {},
+        state => {
+            const productIds = basket.map(item => item.product_id);
+            return productIds
+                .map(
+                    productId => state.admin.resources.products.data[productId]
+                )
+                .filter(r => typeof r !== 'undefined')
+                .reduce((prev, next) => {
+                    prev[next.id] = next;
+                    return prev;
+                }, {});
+        }
+    );
+
+    if (!loaded) return null;
 
     return (
         <Paper className={classes.container} elevation={2}>
diff --git a/examples/demo/src/reviews/BulkAcceptButton.js b/examples/demo/src/reviews/BulkAcceptButton.js
index eb5e85b14af..9ee20c05975 100644
--- a/examples/demo/src/reviews/BulkAcceptButton.js
+++ b/examples/demo/src/reviews/BulkAcceptButton.js
@@ -1,34 +1,47 @@
-import React, { useCallback } from 'react';
+import React from 'react';
 import PropTypes from 'prop-types';
-import { useDispatch } from 'react-redux';
 import ThumbUp from '@material-ui/icons/ThumbUp';
-import { Button, startUndoable, crudUpdateMany } from 'react-admin';
+import { Button, useMutation, UPDATE_MANY } from 'react-admin';
 
-const BulkAcceptButton = ({ basePath, resource, selectedIds }) => {
-    const dispatch = useDispatch();
+const options = {
+    undoable: true,
+    onSuccess: {
+        notification: {
+            body: 'resources.reviews.notification.approved_success',
+            level: 'info',
+        },
+        redirectTo: '/reviews',
+    },
+    onFailure: {
+        notification: {
+            body: 'resources.reviews.notification.approved_error',
+            level: 'warning',
+        },
+    },
+};
 
-    const handleClick = useCallback(() => {
-        dispatch(
-            startUndoable(
-                crudUpdateMany(
-                    resource,
-                    selectedIds,
-                    { status: 'accepted' },
-                    basePath
-                )
-            )
-        );
-    }, [basePath, dispatch, resource, selectedIds]);
+const BulkAcceptButton = ({ selectedIds }) => {
+    const [approve, { loading }] = useMutation(
+        {
+            type: UPDATE_MANY,
+            resource: 'reviews',
+            payload: { ids: selectedIds, data: { status: 'accepted' } },
+        },
+        options
+    );
 
     return (
-        <Button label="resources.reviews.action.accept" onClick={handleClick}>
+        <Button
+            label="resources.reviews.action.accept"
+            onClick={approve}
+            disabled={loading}
+        >
             <ThumbUp />
         </Button>
     );
 };
 
 BulkAcceptButton.propTypes = {
-    resource: PropTypes.string.isRequired,
     selectedIds: PropTypes.arrayOf(PropTypes.any).isRequired,
 };
 
diff --git a/examples/demo/src/reviews/BulkRejectButton.js b/examples/demo/src/reviews/BulkRejectButton.js
index 1d5253abdd1..555de1e1a00 100644
--- a/examples/demo/src/reviews/BulkRejectButton.js
+++ b/examples/demo/src/reviews/BulkRejectButton.js
@@ -1,34 +1,46 @@
-import React, { useCallback } from 'react';
+import React from 'react';
 import PropTypes from 'prop-types';
-import { useDispatch } from 'react-redux';
 import ThumbDown from '@material-ui/icons/ThumbDown';
-import { Button, startUndoable, crudUpdateMany } from 'react-admin';
+import { Button, useMutation, UPDATE_MANY } from 'react-admin';
 
-const BulkRejectButton = ({ basePath, resource, selectedIds }) => {
-    const dispatch = useDispatch();
-
-    const handleClick = useCallback(() => {
-        dispatch(
-            startUndoable(
-                crudUpdateMany(
-                    resource,
-                    selectedIds,
-                    { status: 'rejected' },
-                    basePath
-                )
-            )
-        );
-    }, [basePath, dispatch, resource, selectedIds]);
+const options = {
+    undoable: true,
+    onSuccess: {
+        notification: {
+            body: 'resources.reviews.notification.approved_success',
+            level: 'info',
+        },
+        redirectTo: '/reviews',
+    },
+    onFailure: {
+        notification: {
+            body: 'resources.reviews.notification.approved_error',
+            level: 'warning',
+        },
+    },
+};
+const BulkRejectButton = ({ selectedIds }) => {
+    const [reject, { loading }] = useMutation(
+        {
+            type: UPDATE_MANY,
+            resource: 'reviews',
+            payload: { ids: selectedIds, data: { status: 'rejected' } },
+        },
+        options
+    );
 
     return (
-        <Button label="resources.reviews.action.reject" onClick={handleClick}>
+        <Button
+            label="resources.reviews.action.reject"
+            onClick={reject}
+            disabled={loading}
+        >
             <ThumbDown />
         </Button>
     );
 };
 
 BulkRejectButton.propTypes = {
-    resource: PropTypes.string.isRequired,
     selectedIds: PropTypes.arrayOf(PropTypes.any).isRequired,
 };