我有一个从FormInput组件Map生成的登录表单。
我现在已经根据属性定义的问题类型创建了单独的FormComponents。
但是,由于进行了此更改,我的“凭据”状态不会在用户击键时更新。
我希望凭据状态在击键时更新。但是,目前没有发生这种情况。
登录表单
import React from 'react';
import FormInput from '../../components/Form Input/FormInput';
import { loginInputs } from '../../formSource/formSourceData';
import './Login.scss';
import { useState, useContext } from 'react';
import { useNavigate, Link, useLocation } from 'react-router-dom';
import { useToastContext } from '../../context/toastContext';
import useFetch from '../../Hooks/UseFetch';
import { AuthContext } from '../../context/AuthContext'
import axios from 'axios'
const Login = () => {
const [credentials, setCredentials] = useState({
email: undefined,
password: undefined,
});
const { user, loading, error, dispatch} = useContext(AuthContext)
const { toastDispatch } = useToastContext();
const navigate = useNavigate();
const { state } = useLocation()
const handleChange = (e) => {
console.log(e.target.name)
setCredentials({ ...credentials, [e.target.name]: e.target.value });
console.log(credentials)
};
const handleSubmit = async (e) => {
e.preventDefault()
dispatch({type: "LOGIN_START"})
try{
const res = await axios.post("/api/auth/login", credentials)
dispatch({type:"LOGIN_SUCCESS", payload: res.data})
navigate(state?.path || '/auth/teacher/dashboard');
} catch(err) {
dispatch({type: "LOGIN_FAILURE", payload: err.response.data})
}
}
return (
<div className="container">
<div className="formWrapper">
<h1>Login</h1>
<form className="loginForm" >
{loginInputs.map((input) => (
<FormInput
key={input.id}
{...input}
handleChange={handleChange}
/>
))}
<button type="submit" className="loginButton" onClick={handleSubmit}>
Login
</button>
</form>
<p className="forgotPassword">
<Link to="/forgot-password">Forgot Password</Link>
</p>
<p className="accountText">
Not signed up? <Link to="/register">Register</Link>
</p>
</div>
</div>
);
};
export default Login;
表单输入组件
import { InputRounded } from '@mui/icons-material';
import React, { useState } from 'react';
import './formInput.scss';
const FormInput = (props) => {
const { label, type, errorMessage, handleChange, id, value, ...inputProps } =
props;
const [focused, setFocused] = useState(false);
const [passwordShown, setPasswordShown] = useState(false);
const handleFocus = (e) => {
setFocused(true);
};
const togglePassword = () => {
setPasswordShown(!passwordShown);
};
const Dropdown = () => {
return (
<select
className="formElementInput"
value={value}
name={inputProps.name}
onChange={handleChange}
>
<option className="default" selected disabled>
{inputProps.placeholder}
</option>
{inputProps.options.map((option) => (
<option className="option" value={option}>
{option}
</option>
))}
</select>
);
};
const Input = () => {
return (
<div className="formGroup">
<input
className="formElementInput"
value={value}
name={props.name}
placeholder={props.placeholder}
type={passwordShown ? 'text' : type}
onChange={props.handleChange}
onBlur={handleFocus}
focused={focused.toString()}
onFocus={() =>
inputProps.name === 'confirmPassword' && setFocused(true)
}
/>
<span className="icon" onClick={togglePassword}>
{passwordShown ? inputProps.icon : inputProps.opposite}
</span>
</div>
);
};
return (
<div className="formElement">
<label className="formElementLabel">{label}</label>
{type === 'dropdown' ? (
<Dropdown />
) : (
<Input/>
)}
<span className="errorMessage">{errorMessage}</span>
</div>
);
};
export default FormInput;
登录输入代码
export const loginInputs = [
{
id: 1,
name: "email",
type: "email",
placeholder: "Email",
label: "Email",
errorMessage: "Enter a valid email address",
required: true
},
{
id: 2,
name: "password",
type: "password",
placeholder: "Password",
label: "Password",
errorMessage: "A password should be more than 8 characters.",
required: true,
icon: <Visibility/>,
opposite: <VisibilityOff/>
}
]
这是分离前的原始工作代码。
import { InputRounded } from '@mui/icons-material';
import React, { useState } from 'react';
import './formInput.scss';
const FormInput = (props) => {
const { label, type, errorMessage, handleChange, id, value, ...inputProps } =
props;
const [focused, setFocused] = useState(false);
const [passwordShown, setPasswordShown] = useState(false);
const handleFocus = (e) => {
setFocused(true);
};
const togglePassword = () => {
setPasswordShown(!passwordShown);
};
const Dropdown = () => {
return (
<select
className="formElementInput"
value={value}
name={inputProps.name}
onChange={handleChange}
>
<option className="default" selected disabled>
{inputProps.placeholder}
</option>
{inputProps.options.map((option) => (
<option className="option" value={option}>
{option}
</option>
))}
</select>
);
};
const Input = () => {
return (
<div className="formGroup">
<input
className="formElementInput"
value={value}
name={props.name}
placeholder={props.placeholder}
type={passwordShown ? 'text' : type}
onChange={props.handleChange}
onBlur={handleFocus}
focused={focused.toString()}
onFocus={() =>
inputProps.name === 'confirmPassword' && setFocused(true)
}
/>
<span className="icon" onClick={togglePassword}>
{passwordShown ? inputProps.icon : inputProps.opposite}
</span>
</div>
);
};
return (
<div className="formElement">
<label className="formElementLabel">{label}</label>
{type === 'dropdown' ? (
<select
className="formElementInput"
value={value}
name={inputProps.name}
onChange={handleChange}
>
<option className="default" selected disabled>
{inputProps.placeholder}
</option>
{inputProps.options.map((option) => (
<option className="option" value={option} >
{option}
</option>
))}
</select>
) : (
<div className="formGroup">
<input
className="formElementInput"
value={value}
name={inputProps.name}
placeholder={inputProps.placeholder}
type={passwordShown ? "text" : type}
onChange={handleChange}
onBlur={handleFocus}
focused={focused.toString()}
onFocus={() =>
inputProps.name === 'confirmPassword' && setFocused(true)
}
/>
<span className="icon" onClick={togglePassword}>
{passwordShown ? inputProps.icon : inputProps.opposite}
</span>
</div>
)}
<span className="errorMessage">{errorMessage}</span>
</div>
);
};
export default FormInput;
这里有一个代码沙箱的链接,它展示了我上面解释过的相同行为。
https://codesandbox.io/s/thirsty-feather-9fwwwy?file=/src/App.js
1条答案
按热度按时间fhg3lkii1#
原因是
FormComponent.jsx
中的<Input />
组件是受控的..因此它在呈现的输入字段中查找value
属性,但找不到任何属性:因为..没有任何:
要解决这个问题,可以根据
credentials
状态提供一个value属性:额外的好处:我注意到每次你在那里输入时,输入都会失去焦点(也许这不是你代码中的问题,只是你提供的沙箱中的问题)。
这是因为您在
<FormInput />
中声明了<Input />
,因此每次它发生更改时,它基本上都是从头开始创建<Input />
组件。有很多方法可以实现这一点,但最简单的方法是以三进制内联方式使用它:下面是更新的Sandbox的链接:
https://codesandbox.io/s/epic-poitras-84z4do?file=/Login.jsx:943-995