在模态中使用 Mapbox 时,如何解决未捕获(承诺中)类型错误:无法读取 null 的属性(读取“setAttribute”)?

问题描述 投票:0回答:1

我试图将输入地址自动填充合并到模态中。出现自动填充建议,但是当我尝试单击/选择首选地址时,发生错误并且模式关闭。我手动编码了模式。没有使用样式库。

这是我的模态代码:

import { cloneElement, createContext, useContext, useState } from 'react';
import { useClickOutside } from '../hooks/useClickOutside';
import { createPortal } from 'react-dom';
import { HiXMark } from 'react-icons/hi2';

const ModalContext = createContext();

function Modal({ children }) {
  const [openName, setOpenName] = useState('');

  const close = () => setOpenName('');
  const open = setOpenName;

  return (
    <ModalContext.Provider value={{ openName, close, open }}>
      {children}
    </ModalContext.Provider>
  );
}

function Open({ children, opens: opensWindowName }) {
  const { open } = useContext(ModalContext);

  // return cloneElement(children, { onClicsk: () => console.log('oyeah') });
  return cloneElement(children, { onClick: () => open(opensWindowName) });
}

function Window({ children, name }) {
  const { openName, close } = useContext(ModalContext);

  const ref = useClickOutside(close);

  if (name !== openName) return null;

  // createPortal set the element to the desired parent element
  return createPortal(
    <div className="fixed left-0 top-0 z-[1000] h-full w-full backdrop-blur-sm transition-all">
      <div
        className="fixed left-[50%] top-[50%] -translate-x-1/2 -translate-y-1/2 rounded-md bg-grey-0 px-8 py-6 shadow-lg transition-all"
        ref={ref}
      >
        <button className="absolute right-1 top-1 translate-x-px translate-y-px rounded-md p-1 text-grey-500 transition-all hover:bg-grey-100">
          <HiXMark onClick={close} className="h-6 w-6" />
        </button>
        {cloneElement(children, { onCloseModal: close })}
      </div>
    </div>,
    document.body,
  );
}

Modal.Open = Open;
Modal.Window = Window;

export default Modal;

这是我的创建部署代码:

import { useForm } from 'react-hook-form';
import FormRow from '../../ui/FormRow';
import { useCreateDeployment } from './useCreateDeployment';
import { useEditDeployment } from './useEditDeployment';
import { DayPicker, getDefaultClassNames } from 'react-day-picker';
import { useEffect, useState } from 'react';
import { add } from 'date-fns';
import 'react-day-picker/dist/style.css';
import { AddressAutofill } from '@mapbox/search-js-react';

function CreateDeployment({ deploymentToEdit = {}, onCloseModal }) {
  const [selected, setSelected] = useState({ from: undefined, to: undefined });
  const maxDate = add(new Date(), { years: 1 });
  const { from: fromDate, to: toDate } = selected;

  // console.log(deploymentToEdit);

  const handleSelect = (selectedRange) => {
    if (selectedRange === undefined) return;
    setSelected(selectedRange);
  };

  const { isCreating, createDeployment } = useCreateDeployment();
  const { isEditing, editDeployment } = useEditDeployment();
  const isWorking = isCreating || isEditing;

  const { deploymentId: editId, ...editValues } = deploymentToEdit;
  const isEditSession = Boolean(editId);

  const { register, handleSubmit, reset, formState } = useForm({
    defaultValues: isEditSession ? editValues : {},
  });

  const { errors } = formState;
  const defaultClassNames = getDefaultClassNames();

  function onSubmit(data) {
    // console.log(data);
    if (isEditSession)
      editDeployment(
        {
          newDeploymentData: { ...data },
          deploymentId: editId,
        },
        { onSuccess: (data) => reset() },
        onCloseModal?.(),
      );
    else
      createDeployment(
        { ...data, startDate: selected.from, endDate: selected.to },
        { onSuccess: (data) => reset() },
        onCloseModal?.(),
      );
  }

  return (
    <form
      className="max-h-100 w-[40rem] text-lg"
      onSubmit={handleSubmit(onSubmit)}
    >
      <div className="max-h-[40rem] overflow-y-auto">
        <FormRow
          label="Deployment Name"
          error={errors?.deploymentName?.message}
        >
          <input
            className="rounded-md border border-solid border-grey-300 bg-grey-0 px-4 py-2 shadow-sm"
            {...register('deploymentName', {
              required: 'This field is required',
            })}
            disabled={isWorking}
          />
        </FormRow>
        <FormRow
          label="Number of Personnel"
          error={errors?.numberOfPersonnel?.message}
        >
          <input
            className="rounded-md border border-solid border-grey-300 bg-grey-0 px-4 py-2"
            {...register('numberOfPersonnel', {
              required: 'This field is required',
            })}
          />
        </FormRow>
        <FormRow
          label="Number of Resources"
          error={errors?.numberOfResources?.message}
        >
          <input
            className="rounded-md border border-solid border-grey-300 bg-grey-0 px-4 py-2"
            {...register('numberOfResources', {
              required: 'This field is required',
            })}
            disabled={isWorking}
          />
        </FormRow>
        <FormRow label="Location" error={errors?.location?.message}>
          {/* <input
            className="rounded-md border border-solid border-grey-300 bg-grey-0 px-4 py-2"
            {...register('location', {
              required: 'This field is required',
            })}
            disabled={isWorking}
          /> */}
          <AddressAutofill accessToken="Token">
            <input
              className="rounded-md border border-solid border-grey-300 bg-grey-0 px-4 py-2"
              // name="address-1"
              // autoComplete="address-line1"
            />
          </AddressAutofill>
        </FormRow>

        <div className="flex flex-col items-center border-b border-grey-100 pt-4">
          <div className="m-auto flex">
            <p className="mx-10 px-4 text-sm font-medium text-grey-700">
              From Date:{' '}
              {fromDate ? fromDate.toLocaleDateString() : 'Not selected'}
            </p>

            <p className="mx-10 px-10 text-sm font-medium text-grey-700">
              End Date: {toDate ? toDate.toLocaleDateString() : 'Not selected'}
            </p>
          </div>
          <DayPicker
            classNames={{
              root: `${defaultClassNames.root} scale-75 text-base font-medium text-grey-700 `,
              months: `flex gap-10`,
              range_start: `rounded-full bg-brand-500 opacity-2- text-grey-200`,
              range_end: `rounded-full bg-brand-500 opacity-2- text-grey-200`,
              today: `font-bold text-brand-500`,
              selected: `bg-brand-300 font-medium text-brand-200`,
              chevron: `${defaultClassNames.chevron} fill-brand-500`,
            }}
            mode="range"
            selected={selected}
            onSelect={handleSelect}
            startMonth={new Date()}
            endMonth={maxDate}
            captionLayout="dropdown-months"
            numberOfMonths={2}
            disabled={{
              before: new Date(),
              after: maxDate,
            }}
          />
        </div>

        <FormRow label="Status" error={errors?.status?.message}>
          <select
            className="rounded-md border border-solid border-grey-300 bg-grey-0 px-4 py-2"
            {...register('status', {
              required: 'This field is required',
            })}
            disabled={isWorking}
          >
            <option value="Pending">Pending</option>
            <option value="Ongoing">Ongoing</option>
          </select>
        </FormRow>

        <FormRow label="OPR" error={errors?.opr?.message}>
          <input
            className="rounded-md border border-solid border-grey-300 bg-grey-0 px-4 py-2"
            {...register('opr', {
              required: 'This field is required',
            })}
            disabled={isWorking}
          />
        </FormRow>
        <FormRow
          className="!bg-red-600"
          label="Description"
          error={errors?.description?.message}
        >
          <textarea
            className="h-28 w-56 rounded-md border border-solid border-grey-300 bg-grey-0 px-4 py-2"
            {...register('description', {
              required: 'This field is required',
            })}
            disabled={isWorking}
          />
        </FormRow>

        <div className="flex justify-end">
          <button
            className="btn-secondary mx-2 mt-[auto]"
            type="reset"
            onClick={() => onCloseModal?.()}
            disabled={isWorking}
          >
            Cancel
          </button>
          <button
            type="submit"
            className="btn-primary mx-2 mt-5"
            disabled={isWorking}
          >
            Submit
          </button>
        </div>
      </div>
    </form>
  );
}

export default CreateDeployment;

这是我每次尝试单击建议地址时遇到的错误:

enter image description here

我已经在 Createeployment 组件中直接测试了自动填充功能,并且它可以工作,因此仅当在模态模式中使用 Createdeployment 时。

reactjs mapbox-gl-js
1个回答
0
投票
Mapbox 自动填充组件需要

name
autoComplete
属性。取消注释这些属性可以解决问题。

<AddressAutofill accessToken="Token">
  <input
    className="rounded-md border border-solid border-grey-300 bg-grey-0 px-4 py-2"
    name="address-1"
    autoComplete="address-line1"
  />
</AddressAutofill>

© www.soinside.com 2019 - 2024. All rights reserved.