开发者问题收集

删除前使用确认对话框仍然失败

2022-04-20
1276

我想向 react-admin 添加一条确认消息,例如“您想删除项目吗?”。

因此,我尝试使用 <DeleteButton />undoable={false> 选项以及 <DeleteWithConfirmButton /> 组件

但是它们两个都一直发生这样的错误。

Uncaught TypeError: Cannot read properties of undefined (reading 'toLowerCase')

at Object.humanize (inflection.js:828:1)
at DeleteWithConfirmButton (DeleteWithConfirmButton.js:53:1)
at renderWithHooks (react-dom.development.js:14803:1) . . .

问题

看起来 <DeleteWithConfirmButton /> 是一个问题。 ( <DeleteButton undoable={false} /> 也在内部调用 <DeleteWithConfirmButton /> 。)

  1. 调用 <DeleteWithConfirmButton />

  2. 它们在 <Confirm .. TranslationOptions={} ... /> 中调用 inflection.humanize

  3. inflection.humanize 使用 toLowerCase() 方法,但 translateOption 没有传递正确的字符串( resources.${resource}.name )。

  4. 发生错误。

发生此错误是因为没有 resources.${resource}.name 在我的 props 中?我该如何修复它?

我的代码

const BottomToolbar = (props: EditActionsProps) => {

  return (
  // eslint-disable-next-line react/jsx-props-no-spreading
    <Toolbar {...props}>
      <SaveButton style={toolBarStyle} label="member.edit.editButton" />
      <DeleteButton label="member.edit.deleteButton" />
      <DeleteWithConfirmButton />
    </Toolbar>
  );
};
export interface EditActionsProps {
    basePath?: string;
    className?: string;
    data?: Record;
    hasCreate?: boolean;
    hasEdit?: boolean;
    hasList?: boolean;
    hasShow?: boolean;
    resource?: string;
}
// my props looks like this
record:
    firstSeenAt: t {seconds: 1502878077, nanoseconds: 0}
    groupId: "ldjapon18073hk"
    id: "pQ--------"
    lastSeenAt: t {seconds: 16000000, nanoseconds: 5700000000}
    managerId: "Me------"
    memberName: "xxx"
    totalTrainedTimeInSec: 37.882999999999996
redirect: "list"
resource: "members"

此代码是 <DeleteWithConfirmButton /> 组件代码。

const {
        basePath,
        classes: classesOverride,
        className,
        confirmTitle = 'ra.message.delete_title',
        confirmContent = 'ra.message.delete_content',
        icon = defaultIcon,
        label = 'ra.action.delete',
        mutationMode,
        onClick,
        record,
        redirect = 'list',
        onSuccess,
        onFailure,
        ...rest
    } = props;
    const translate = useTranslate();
    const classes = useStyles(props);
    const resource = useResourceContext(props);
    const {
        open,
        loading,
        handleDialogOpen,
        handleDialogClose,
        handleDelete,
    } = useDeleteWithConfirmController({
        record,
        redirect,
        basePath,
        mutationMode,
        onClick,
        onSuccess,
        onFailure,
        resource,
    });
return (
        <Fragment>
            <Button
                onClick={handleDialogOpen}
                label={label}
                className={classnames(
                    'ra-delete-button',
                    classes.deleteButton,
                    className
                )}
                key="button"
                {...rest}
            >
                {icon}
            </Button>
            <Confirm
                isOpen={open}
                loading={loading}
                title={confirmTitle}
                content={confirmContent}
                /* Error occur here! */
                translateOptions={{
                    name: translate(`resources.${resource}.forcedCaseName`, {
                        smart_count: 1,
                        _: inflection.humanize(
                            translate(`resources.${resource}.name`, {
                                smart_count: 1,
                                _: inflection.singularize(resource),
                            }),
                            true
                        ),
                    }),
                    id: record.id,
                }}
                onConfirm={handleDelete}
                onClose={handleDialogClose}
            />
        </Fragment>
    );

这是 inflection.js

**/**
   * This function adds humanize support to every String object.
   * @public
   * @function
   * @param {String} str The subject string.
   * @param {Boolean} low_first_letter Default is to capitalize the first letter of the results.(optional)
   *                                 Passing true will lowercase it.
   * @returns {String} Lower case underscored words will be returned in humanized form.
   * @example
   *
   *     var inflection = require( 'inflection' );
   *
   *     inflection.humanize( 'message_properties' ); // === 'Message properties'
   *     inflection.humanize( 'message_properties', true ); // === 'message properties'
   */
    humanize : function ( str, low_first_letter ){
      str = str.toLowerCase(); // Line 828 : Error Occur in here!
      str = str.replace( id_suffix, '' );
      str = str.replace( underbar, ' ' );

      if( !low_first_letter ){
        str = inflector.capitalize( str );
      }

      return str;
    },
**
2个回答

我认为因为你没有给 DeleteWithConfirmButton 提供 props,所以它有错误

在你的代码中:

const BottomToolbar = (props: EditActionsProps) => {

  return (
  // eslint-disable-next-line react/jsx-props-no-spreading
    <Toolbar {...props}>
      <SaveButton style={toolBarStyle} label="member.edit.editButton" />
      <DeleteButton label="member.edit.deleteButton" />
      <DeleteWithConfirmButton props={props}/>
      // In here, you need provider prop for DeleteWithConfirmButton component
    </Toolbar>
  );
};
Quyen Nguyen
2022-04-20

对于未来遇到同样问题的用户..

我在我的项目中使用`“react-admin”:“3.13.4”。

DeleteWithConfirmButton.propTypes 中没有 translateOptions ,并且 translateOptions 也没有默认值。所以我无法直接传递 translateOptions ,并且没有默认值。这就是我发生错误的原因。

值得庆幸的是,这个 错误已在 v4.0.0 中修复 。我更新了我的版本, <DeleteWithConfirmButton /> 可以正常工作。

Lucy
2022-04-20