我正在构建一个带有尾风的动态警报UI。我希望发出此警报,以便在发出所有请求时可以在任何地方使用。我还将警报与全局状态中的值结合起来。总的来说,它运行得很好,但是有以下几点警告:

这是使用redux工具的全局警报状态:
import { createSlice } from '@reduxjs/toolkit';
const uiSlice = createSlice({
name: 'UI',
initialState: {
offcanvasVisible: false,
alert: {
isShow: false,
variant: '',
message: '',
},
},
reducers: {
offcanvasToggle: (state) => {
state.offcanvasVisible = !state.offcanvasVisible;
},
showAlert: (state, action) => {
state.alert.isShow = true;
state.alert.message = action.payload.message;
state.alert.variant = action.payload.variant;
},
closeAlert: (state) => {
state.alert.isShow = false;
state.alert.message = '';
state.alert.variant = '';
},
},
});
export const { offcanvasToggle, showAlert, closeAlert } = uiSlice.actions;
export default uiSlice.reducer;警报组件中的下列代码:
import { BiNoEntry } from 'react-icons/bi';
import { IoCloseSharp } from 'react-icons/io5';
import { BsCheckCircleFill, BsFillInfoCircleFill } from 'react-icons/bs';
import { useDispatch, useSelector } from 'react-redux';
import { closeAlert } from '../../store/ui-slice';
import { useEffect, useState } from 'react';
const Alert = () => {
const [showState, setShowState] = useState(false);
const [variantState, setVariantState] = useState('');
const [messageState, setMessageState] = useState('');
const [classes, setClasses] = useState('');
const dispatch = useDispatch();
const { variant, message, isShow } = useSelector((state) => state.ui.alert);
useEffect(() => {
if (!isShow) return;
setShowState(isShow);
setVariantState(variant);
setMessageState(message);
if (variant === 'info') {
setClasses('bg-blue-400 border-blue-500');
}
if (variant === 'success') {
setClasses('bg-green-400 border-green-500');
}
if (variant === 'failed') {
setClasses('bg-red-400 border-red-500');
}
}, [isShow, variant, message]);
return (
<div
className={`${
!showState && 'hidden'
} container-custom w-full py-4 text-white flex flex-row gap-2 items-center justify-between ${classes}`}
>
<div className="flex flex-row gap-2 items-center">
<span>
{variantState === 'info' ? (
<BsFillInfoCircleFill size="24" />
) : variantState === 'success' ? (
<BsCheckCircleFill size="24" />
) : variantState === 'failed' ? (
<BiNoEntry size="24" />
) : (
''
)}
</span>
{messageState}
</div>
<button
onClick={() => {
dispatch(closeAlert());
}}
className="text-white"
>
<IoCloseSharp color="white" size="24" />
</button>
</div>
);
};
export default Alert;联系人组件中的代码:
/* eslint-disable jsx-a11y/iframe-has-title */
import LandingLayout from '../../components/Layout/LandingLayout';
import Breadcrumb from '../../components/UI/Breadcrumb';
import Input from '../../components/Form/Input';
import TextArea from '../../components/Form/TextArea';
import { AiOutlineWhatsApp } from 'react-icons/ai';
import { BsInstagram } from 'react-icons/bs';
import {
MdOutlineAddLocationAlt,
MdOutlineEmail,
MdPhone,
} from 'react-icons/md';
import Button from '../../components/UI/Button';
import { useForm } from 'react-hook-form';
import { useDispatch, useSelector } from 'react-redux';
import {
sendingEmail,
turnOffLoadingSendEmail,
turnOnLoadingSendEmail,
} from '../../store/landing-slice';
import Spin from '../../components/UI/Spin';
import { showAlert } from '../../store/ui-slice';
const Kontak = () => {
const dispatch = useDispatch();
const { loading, success, error } = useSelector(
(state) => state.landing.sendEmail
);
const {
register,
handleSubmit,
formState: { errors, isValid },
reset,
} = useForm({
mode: 'all',
});
if (success !== null) {
dispatch(showAlert({ variant: 'success', message: success.message }));
}
const onSubmit = (data) => {
if (!isValid) return;
dispatch(turnOnLoadingSendEmail());
setTimeout(() => {
dispatch(sendingEmail(data));
dispatch(turnOffLoadingSendEmail());
reset();
}, 1000);
};
return (
<LandingLayout>
<Breadcrumb title="Kontak Kami" />
<section className="container-custom py-10 w-full h-[450px] overflow-hidden">
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3960.687915874803!2d107.64700641530236!3d-6.927857094994467!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x2e68e80a699f1971%3A0xca4c51951a56650c!2sPanti%20Asuhan%20Al-Hidayah!5e0!3m2!1sid!2sid!4v1666696368586!5m2!1sid!2sid"
width="100%"
height="100%"
style={{ border: 0 }}
allowFullScreen=""
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
/>
</section>
<section className="container-custom py-4 w-full flex flex-col gap-10 md:flex-row-reverse">
<form onSubmit={handleSubmit(onSubmit)} className="w-full">
<h2 className="text-gray-700 text-lg mb-3">
Hubungi kami melalui form dibawah ini.
</h2>
<div className="flex flex-col lg:flex-row lg:gap-3">
<Input
options={{
...register('name', {
required: 'Nama Lengkap tidak boleh kosong',
}),
}}
id="name"
label="Nama Lengkap"
requireIcon="true"
hasError={!!errors?.name}
errorMessage={errors?.name?.message}
/>
<Input
options={{
...register('email', {
required: 'E-Mail tidak boleh kosong',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
}),
}}
id="email"
label="E-Mail"
requireIcon="true"
hasError={!!errors?.email}
errorMessage={errors?.email?.message}
/>
</div>
<Input
options={{
...register('subject', { required: 'Subjek tidak boleh kosong' }),
}}
id="subject"
label="Subjek"
requireIcon="true"
hasError={!!errors?.subject}
errorMessage={errors?.subject?.message}
/>
<TextArea
id="keterangan"
label="Keterangan"
options={{
...register('keterangan'),
rows: '4',
}}
></TextArea>
<Button
className="flex gap-2"
options={{
type: 'submit',
disabled: !isValid,
}}
>
{loading && <Spin />}
Kirim
</Button>
</form>
<div className="w-full flex flex-col gap-2 md:gap-4">
<div className="flex flex-row gap-2">
<span className="self-start rounded-full bg-gray-300 text-gray-700 p-3">
<MdOutlineAddLocationAlt size={32} />
</span>
<div className="flex flex-col gap-1">
<h3 className="pt-5 font-semibold text-[17px]">Alamat</h3>
Jl. Trs. St. Kiaracondong, RT.02/RW.08, Kebun Jayanti, Kec.
Kiaracondong, Kota Bandung, Jawa Barat 40281
</div>
</div>
<div className="flex flex-row gap-2">
<span className="self-start rounded-full bg-gray-300 text-gray-700 p-3">
<MdPhone size={32} />
</span>
<div className="flex flex-col gap-1">
<h3 className="pt-5 font-semibold text-[17px]">Telepon</h3>
022 7333116
</div>
</div>
<div className="flex flex-row gap-2">
<span className="self-start rounded-full bg-gray-300 text-gray-700 p-3">
<AiOutlineWhatsApp size={32} />
</span>
<div className="flex flex-col gap-1">
<h3 className="pt-5 font-semibold text-[17px]">Whatsapp</h3>
0882 43556 7721
</div>
</div>
<div className="flex flex-row gap-2">
<span className="self-start rounded-full bg-gray-300 text-gray-700 p-3">
<BsInstagram size={32} />
</span>
<div className="flex flex-col gap-1">
<h3 className="pt-5 font-semibold text-[17px]">Instagram</h3>
yayasan_alhidayah
</div>
</div>
<div className="flex flex-row gap-2">
<span className="self-start rounded-full bg-gray-300 text-gray-700 p-3">
<MdOutlineEmail size={32} />
</span>
<div className="flex flex-col gap-1">
<h3 className="pt-5 font-semibold text-[17px]">E-Mail</h3>
alhidayahkircon@gmail.com
</div>
</div>
</div>
</section>
</LandingLayout>
);
};
export default Kontak;我把警报放进了海军:
import { Link } from 'react-router-dom';
import Logo from '../UI/Logo';
import { FiMenu, FiPhone } from 'react-icons/fi';
import Button from '../UI/Button';
import Dropdown from '../UI/Dropdown';
import { BiDonateHeart } from 'react-icons/bi';
import { AiOutlineHistory } from 'react-icons/ai';
import Alert from '../UI/Alert';
const Navbar = (props) => {
return (
<header className="sticky top-0 z-10 bg-white border-b-2 border-slate-200">
<Alert />
<div className="container-custom flex justify-between items-center">
<div className="w-36 pl-2 md:pl-0">
<Link to="/">
<Logo />
</Link>
</div>
<ul className="hidden lg:flex font-medium">
<li className="mr-1 hover:bg-gray-100 py-2 px-4 rounded-md">
<Link to={'/'}>Beranda</Link>
</li>
<li className="mr-1 hover:bg-gray-100 py-2 px-4 rounded-md">
<Link to={'/kegiatan'}>Kegiatan</Link>
</li>
<li className="mr-1 hover:bg-gray-100 py-2 px-4 rounded-md">
<Dropdown label="Donasi">
<li className="block px-4 py-2 hover:bg-gray-100">
<Link className="flex items-center" to="/donasi">
<span className="mr-3">
<BiDonateHeart />
</span>
Formulir Donasi
</Link>
</li>
<li className="block px-4 py-2 hover:bg-gray-100">
<Link className="flex items-center" to="/cek-donasi">
<span className="mr-3">
<AiOutlineHistory />
</span>
<p>Cek Donasi</p>
</Link>
</li>
</Dropdown>
</li>
<li className="mr-1 hover:bg-gray-100 py-2 px-4 rounded-md">
<Dropdown label="Tentang Kami">
<li className="block px-4 py-2 hover:bg-gray-100">
<Link to="/profil-lembaga">Profil Lembaga</Link>
</li>
<li className="block px-4 py-2 hover:bg-gray-100">
<Link to="/visi-misi">Visi & Misi</Link>
</li>
<li className="block px-4 py-2 hover:bg-gray-100">
<Link to="/galeri">
<p>Galeri</p>
</Link>
</li>
<li className="block px-4 py-2 hover:bg-gray-100">
<Link to="/kontak">Hubungi Kami</Link>
</li>
</Dropdown>
</li>
</ul>
<div className="hidden lg:grid grid-cols-2 gap-1">
<a
className="flex items-center mr-1 hover:bg-gray-100 py-2 px-4 rounded-md"
href="tel:+0222334645"
>
<FiPhone size={'24'} />
<span className="ml-2">022 2334645</span>
</a>
<Button
className="flex justify-center items-center"
options={{
type: 'link',
href: '/donasi',
}}
>
Donasi
<span className="ml-1">
<BiDonateHeart />
</span>
</Button>
</div>
<div className="lg:hidden" onClick={props.offcanvasToggle}>
<FiMenu size={32} />
</div>
</div>
</header>
);
};
export default Navbar;下面是UI应该是什么样子:

首先,我感谢你被石化了
我希望我能用最好的方式来实现警报,而没有像这样的警告。
发布于 2022-10-26 12:55:28
这是因为您对状态的更新是级联的。您的第一个set将导致DOM更新。更新尚未完成,因此您的第二个(或第三个) set也试图更新DOM,并导致冲突。
我发现,当我同时更新多个状态变量时,最好使用useReducer而不是useState。然后,您可以设置一个dispatch方法,该方法可以同时更新多个状态位,甚至可以提供多个有条件地进行不同更新的方法。这样,state更新是并发的,并且避免您正在看到的错误。
https://stackoverflow.com/questions/74207917
复制相似问题