我正在尝试创建一个自定义 toast 来显示错误通知。 Toast 的可见性取决于道具的
isShowed
。
export type ToastProps = {
color: 'error' | 'success' | 'warning';
message: string;
isShowed: boolean;
};
const Toast = (props: ToastProps) => {
const { color, message, isShowed } = props;
const [showed, setShowed] = useState(false);
console.log(isShowed, showed);
useEffect(() => {
if (isShowed) {
setShowed(true);
} else {
setShowed(false);
}
}, [isShowed]);
return (
<div
className="toast-notification-wrapper"
style={{
position: 'fixed',
top: '20px',
left: '50%',
transform: 'translateX(-50%)',
zIndex: 9999,
padding: '15px',
borderRadius: '5px',
transition: 'all 0.3s ease-out',
opacity: showed ? 1 : 0,
pointerEvents: showed ? 'auto' : 'none',
display: 'flex',
justifyContent: 'space-between',
minWidth: '150px',
backgroundColor:
color === 'error'
? '#dc3545'
: color === 'success'
? '#28a745'
: '#ffc107',
}}
>
<p style={{ margin: 0, color: 'white', fontSize: '15px', lineHeight: 1 }}>
{message}
</p>
<span
style={{
cursor: 'pointer',
display: 'flex',
alignContent: 'center',
justifyContent: 'center',
marginLeft: '30px',
}}
onClick={() => {
setShowed(!isShowed);
}}
>
<FontAwesomeIcon
icon={faClose}
style={{ color: 'white', fontSize: '15px' }}
/>
</span>
</div>
);
};
这是我的吐司组件
const Login = (props: { isCompleted: boolean; isLoggedIn: boolean }) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [showPassword, setShowPassword] = useState(false);
const navigate = useNavigate();
const [toast, setToast] = useState({
isShowed: false,
color: 'error',
message: 'failed',
} as ToastProps);
const { isCompleted, isLoggedIn } = props;
if (isCompleted === false) {
return null;
}
if (isLoggedIn) {
navigate('/');
}
const togglePasswordVisibility = () => {
setShowPassword(showPassword ? false : true);
};
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
try {
await login({ username, password });
window.location.href = '/';
} catch (error: any) {
setToast({
isShowed: true,
color: 'error',
message:
error.response.data?.message ||
'Unexpected Error. Please try again later',
});
}
};
return (
<div className="login-form">
<Toast
isShowed={toast.isShowed}
color={toast.color}
message={toast.message}
></Toast>
<div className="login-form-container">
<h1>Login</h1>
<form onSubmit={handleSubmit}>
<div className="form-row">
<label>Username</label>
<input
type="text"
placeholder="Enter your username"
required={true}
onChange={e => setUsername(e.target.value)}
></input>
</div>
<div className="form-row">
<label>Password</label>
<input
type={showPassword ? 'text' : 'password'}
placeholder="********"
required={true}
onChange={e => setPassword(e.target.value)}
></input>
<span
onClick={togglePasswordVisibility}
style={{
position: 'absolute',
right: '20px',
top: 'calc(50% + 12px)',
fontSize: '13px',
transform: 'translateY(-50%)',
cursor: 'pointer',
}}
>
<FontAwesomeIcon
icon={showPassword ? faEyeSlash : faEye}
style={{ color: 'black' }}
/>
</span>
</div>
<div className="button-wrapper">
<button value={'Login'}>Login</button>
</div>
</form>
</div>
</div>
);
};
const Login = (props: { isCompleted: boolean; isLoggedIn: boolean }) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [showPassword, setShowPassword] = useState(false);
const navigate = useNavigate();
const [toast, setToast] = useState({
isShowed: false,
color: 'error',
message: 'failed',
} as ToastProps);
const { isCompleted, isLoggedIn } = props;
if (isCompleted === false) {
return null;
}
if (isLoggedIn) {
navigate('/');
}
const togglePasswordVisibility = () => {
setShowPassword(showPassword ? false : true);
};
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
try {
await login({ username, password });
window.location.href = '/';
} catch (error: any) {
setToast({
isShowed: true,
color: 'error',
message:
error.response.data?.message ||
'Unexpected Error. Please try again later',
});
}
};
return (
<div className="login-form">
<Toast
isShowed={toast.isShowed}
color={toast.color}
message={toast.message}
></Toast>
<div className="login-form-container">
<h1>Login</h1>
<form onSubmit={handleSubmit}>
<div className="form-row">
<label>Username</label>
<input
type="text"
placeholder="Enter your username"
required={true}
onChange={e => setUsername(e.target.value)}
></input>
</div>
<div className="form-row">
<label>Password</label>
<input
type={showPassword ? 'text' : 'password'}
placeholder="********"
required={true}
onChange={e => setPassword(e.target.value)}
></input>
<span
onClick={togglePasswordVisibility}
style={{
position: 'absolute',
right: '20px',
top: 'calc(50% + 12px)',
fontSize: '13px',
transform: 'translateY(-50%)',
cursor: 'pointer',
}}
>
<FontAwesomeIcon
icon={showPassword ? faEyeSlash : faEye}
style={{ color: 'black' }}
/>
</span>
</div>
<div className="button-wrapper">
<button value={'Login'}>Login</button>
</div>
</form>
</div>
</div>
);
};
这是我的登录表单组件
当错误事件触发时,Toast 通知第一次起作用。 但是当错误再次发生时,toast仍然不可见。 当我使用 console.log 检查状态时, props 中的
isShowed
为 true,但 showed
为 false。
请帮我。预先感谢。
从 Toast 组件中删除
useEffect
块和 showed
状态,使用以下 ToastProps
export type ToastProps = {
color: 'error' | 'success' | 'warning';
message: string;
handleCloseToast: ()=>void
};
使用handleCloseToast函数来关闭toast
并根据父级中的 Toast 状态,使用以下 Toast 道具
<Toast
handleCloseToast={() => setToast(prev => ({...prev,isShowed:false})}
color={toast.color}
message={toast. Message}
></Toast>
这只是 @IdrisSelimi 所解释的代码形式