开发者问题收集

如何取消选择 React 管理员自定义批量操作按钮中的列表项

2019-01-07
3679

我有一个 React 管理项目,并为传递到 bulkActionButtons 属性的列表视图实现了一个自定义按钮,如下面文档所述: https://marmelab.com/react-admin/List.html#bulk-action-buttons

const BulkUserActions = props => (
  <MakeAdminButton {...props}/>
);

const UserList = props => (
  <List {...props} bulkActionButtons={<BulkUserActions/>}>
    <Datagrid rowClick="show">
      <TextField source="id"/>
      <EmailField source="email"/>
    </Datagrid>
  </List>
);

MakeAdminButton 处理点击并执行我需要的更新。难题中缺少的部分是如何在操作完成后取消选择列表项。 props.selectedIds 受到保护,因此在完成我的逻辑后,我无法简单地将其设置为空数组。

问题是如何取消设置 props.selectedIds 或在完成后取消选择列表项的其他方法。

const MakeAdminButton = withStyles(styles)(class MakeAdminButton extends React.Component {

  handleAction = () => {
    //does the stuff as required using this.props.selectedIds

    //what to return to unset this.props.selectedIds 
  };

  render () {
    return <Button variant="contained"
               color="primary"
               onClick={this.handleAction}
    <AdminIcon/>
  </Button>;
  }
});
3个回答

React Admin 提供了实现此目的的方法。在 v3 上直接使用 useUnselectAll 或在 useMutation、useUpdateMany 和 useDataProvider 钩子的 onSuccess 回调上。在 v2 中使用 withDataProvider 装饰器的 dataProvider 第四个参数或将自定义 redux 操作的 meta.onSuccess.unselectAll 设置为 true,或者使用 crudUpdateMany 自动设置,或者使用 Mutation 组件的 options prop。

对于带有 crudUpdateMany 的 v2, 转到 Mike Miller 的回答。

工作示例:

https://codesandbox.io/s/exciting-firefly-dd1ni?file=/src/App.js

v3:

const UnselectAllButtonV3Hook = props => {
  const unselectAll = useUnselectAll();

  return (
    <Button
      onClick={() => {
        unselectAll(props.resource);
      }}
    >
      Unselect all with v3 hook
    </Button>
  );
};

https://marmelab.com/react-admin/doc/3.5/Actions.html#handling-side-effects-in-usedataprovider

useUpdateMany/useDataProvider/useMutation 钩子,onSuccess 回调从 useUnselectAll() 调用 unselectAll()

const MakeAdminButtonV3 = props => {
  const refresh = useRefresh();
  const unselectAll = useUnselectAll();

  const [makeAdmin, { loading }] = useUpdateMany(
    props.resource,
    props.selectedIds,
    { isAdmin: true },
    {
      onSuccess: () => {
        unselectAll(props.resource);
        refresh();
      }
    }
  );

  //OR

  const dataProvider = useDataProvider();

  const makeAdmin2 = () => {
    dataProvider.updateMany(
      props.resource,
      { ids: props.selectedIds, data: { isAdmin: true } },
      {
        onSuccess: () => {
          unselectAll(props.resource);
          refresh();
        }
      }
    );
  };

  //OR

  const [makeAdmin3, { loading3 }] = useMutation(
    {
      type: "updateMany",
      resource: props.resource,
      payload: { ids: props.selectedIds, data: { isAdmin: true } }
    },
    {
      onSuccess: () => {
        unselectAll(props.resource);
        refresh();
      }
    }
  );

  return (
    <Button onClick={makeAdmin3} disabled={loading3}>
      Make Admin with V3 dataProvider hooks
    </Button>
  );
};

https://marmelab.com/react-admin/doc/3.5/Actions.html#usemutation-hook

https://marmelab.com/react-admin/doc/3.5/Actions.html#usedataprovider-hook

https://marmelab.com/react-admin/doc/3.5/Actions.html#specialized-hooks

V2 示例也适用于 v3,但 Mutation 和 withDataProvider 是遗留的,在使用 dataProvider 时有细微的变化直接,因为 v3 上的 dataProvider api 已更改。

https://marmelab.com/react-admin/doc/3.5/Actions.html#legacy-components-query-mutation-and-withdataprovider

v2:

withDataProvider:

const UnmakeAdminButtonWithWithDataProvider = withDataProvider(
  class extends React.Component {
    handleClick = () => {
      this.props.dataProvider(
        UPDATE_MANY,
        "users",
        { ids: this.props.selectedIds, data: { isAdmin: false } },
        { onSuccess: { unselectAll: true, refresh: true } }
      );
    };

    render() {
      return (
        <Button onClick={this.handleClick}>
          Unmake Admin with withDataProvider
        </Button>
      );
    }
  }
);

https://marmelab.com/react-admin/doc/2.9/Actions.html#handling-side-effects

自定义 redux 操作:

import { connect } from 'react-redux';

const MAKE_ADMIN = "MAKE_ADMIN";

const makeAdmin = ids => ({
  type: MAKE_ADMIN,
  payload: { ids, data: { isAdmin: true } },
  meta: {
    fetch: UPDATE_MANY,
    resource: "users",
    onSuccess: { unselectAll: true, refresh: true }
  }
});

const MakeAdminButtonWithCustomAction = connect(
  null,
  { makeAdmin }
)(
  class extends React.Component {
    handleClick = () => {
      this.props.makeAdmin(this.props.selectedIds);
    };

    render() {
      return (
        <Button onClick={this.handleClick}>
          Make Admin With Custom Redux Action
        </Button>
      );
    }
  }
);

https://marmelab.com/react-admin/doc/2.9/Actions.html#adding-side-effects-to-actions

突变组件:

const MakeAdminMutationV2 = props => (
  <Mutation
    type="updateMany" //{UPDATE_MANY}
    resource={props.resource}
    payload={{ ids: props.selectedIds, data: { isAdmin: true } }}
    options={{
      onSuccess: {
        unselectAll: true,
        refresh: true
      }
    }}
  >
    {approve => <Button onClick={approve}>Make admin with Mutation</Button>}
  </Mutation>
);

https://marmelab.com/react-admin/doc/2.9/Actions.html#query-and-mutation-components

gstvg
2020-05-12

每次单击复选框时设置一些元数据,以便它将 true 或 false 注入数组,例如:

listData = {
   ...
   isChecked : true
}

然后在处理批量操作的函数内部,添加一个 [listData].filter() ,(lodash 过滤器速度更快),以检查并查看哪个 isChecked === true ,然后将它们设置为 false,并更新复选框输入标签上的 value={bool 属性。

joe hoeller
2019-01-07

解决方案是从 react admin 调用批量辅助函数:

class MakeAdminButton extends React.Component {

handleAction = () => {
 const { basePath, crudUpdateMany, resource, selectedIds } = this.props;

 //custom code goes in here...

 //calling this function triggers the unset and closes the toolbar
 crudUpdateMany(resource, selectedIds, { isAdmin: true }, basePath);
 };

render () {
  return <Button label="Make Admin" onClick={this.handleAction}>
    <AdminIcon/>
  </Button>;
 }
};

const BulkUserActions = connect(undefined, { crudUpdateMany })(MakeAdminButton);

const UserList = props => (
 <List {...props} bulkActionButtons={<BulkUserActions/>}>
  <Datagrid>
   <TextField source="id"/>
   <EmailField source="email"/>
   <BooleanField source="isAdmin" label="Admin" />
 </Datagrid>
</List>
);

如果我仔细阅读的话,此页面上会显示一个示例: https://github.com/marmelab/react-admin/blob/master/docs/List.md#bulk-action-buttons

Mike Miller
2019-01-07