模态框中使用Mapbox地址自动补全时出现TypeError错误的解决方法
问题:Mapbox地址自动补全在自定义模态框中点击选择时触发错误并关闭模态框
我手动实现了一个无第三方样式库依赖的模态框,在其中集成Mapbox地址自动补全功能后,地址建议列表可以正常显示,但点击选择地址时会触发以下错误:Uncaught (in promise) TypeError: Cannot read properties of null (reading 'setAttribute')
同时模态框会自动关闭。单独使用CreateDeployment组件时该功能完全正常,仅在模态框内使用时出现此问题。
模态框代码
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, { onClick: () => open(opensWindowName) }); } function Window({ children, name }) { const { openName, close } = useContext(ModalContext); const ref = useClickOutside(close); if (name !== openName) return null; 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;
CreateDeployment组件代码
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; 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) { 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}> <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;
错误截图

内容的提问来源于stack exchange,提问作者JungProg
相关产品推荐
相关产品推荐

