В настоящее время я пишу страницу регистрации с помощью react-js с реагирующими хуками, и я все еще учусь, поэтому, пожалуйста, извините меня, если это очень простой вопрос.
У меня есть signup.js, написанный в функциональном компоненте с хуками. signup.js импортирует 'EmailTextField', 'PasswordTextField', 'NameTextField', 'CellPhoneTextField'... компоненты которых также прописаны в функциональных компонентах с хуками.
Я сделал все эти текстовые поля отдельными компонентами, чтобы упростить код, поскольку у меня есть требование иметь много разных проверок для каждого текстового поля. (и наличие всех этих полей на странице signup.js делает очень длинный код)
В конце процесса в signup.js я хотел бы получить состояние всех его подкомпонентов (всех этих текстовых полей) (независимо от того, подходит ли пользователь для входа или нет.), но я не уверен, как пройти состояние (или переменная) от этих текстовых полей до signup.js.
Я знаю, что избыточность может управлять состоянием, но можно ли добиться этого без избыточности?
Спасибо.
Я создал Образец CodeSandbox с минимальным примером кода для работы.
Здесь я использую компонент EmailTextfield в apptest.js. Я хотел бы получить состояние isValid на EmailTextfield от apptest.js, чтобы я мог убедиться, что все поля проверены до того, как пользователь зарегистрируется.
'./components/UI/Textfield/EmailTextField.js'
import React, { useState } from "react";
import TextField from "@material-ui/core/TextField";
import Grid from "@material-ui/core/Grid";
export const EmailTextField = props => {
const [value, setValue] = useState("");
const [helperText, setHelperText] = useState(
"Email address will be used as your username."
);
const [isValid, setIsValid] = useState("true");
const handleOnChangeEmailAddress = event => {
// Email Validation logic
if (true) {
setIsValid(true);
} else {
setIsValid(false);
}
};
return (
<Grid item xs = {12}>
<TextField
variant = "outlined"
required
fullWidth
id = "email"
label = "email address"
error = {!isValid}
helperText = {helperText}
name = "email"
autoComplete = "email"
margin = "dense"
onBlur = {handleOnChangeEmailAddress}
/>
</Grid>
);
};
export default EmailTextField;
'aptest.js'
import React from "react";
import CssBaseline from "@material-ui/core/CssBaseline";
import Grid from "@material-ui/core/Grid";
import { makeStyles } from "@material-ui/core/styles";
import Container from "@material-ui/core/Container";
import { EmailTextField } from "./components/UI/Textfield/EmailTextField";
const useStyles = makeStyles(theme => ({
"@global": {
body: {
backgroundColor: theme.palette.common.white
}
},
paper: {
marginTop: theme.spacing(8),
display: "flex",
flexDirection: "column",
alignItems: "center"
},
mainBox: {
// margin: '200px',
width: "550px",
textAlign: "left",
boxShadow: "0 2px 3px #ccc",
border: "1px solid #eee",
padding: "40px 70px 50px 70px",
boxSizing: "border-box"
},
form: {
width: "100%", // Fix IE 11 issue.
marginTop: theme.spacing(3)
}
}));
const Apptest = props => {
const classes = useStyles();
return (
<Container component = "main" maxWidth = "xs">
<CssBaseline />
<div className = {classes.paper}>
<div className = {classes.mainBox}>
<form className = {classes.form} noValidate>
<Grid container spacing = {2}>
<EmailTextField />
</Grid>
</form>
</div>
</div>
</Container>
);
};
export default Apptest;
Я загрузил пример кода в codeandbox.io/embed/cranky-glade-82leu
В этом примере у меня есть только один компонент с именем EmailTextField.js. Я хотел бы получить состояние «IsValid» от компонента на apptest.js.





Я имею в виду очень грубую реализацию.
Вокруг полей ввода должна быть согласованная модель данных. Эта модель данных должна быть единственным источником правды для этого конкретного поля ввода. Он должен быть в состоянии сказать, было ли затронуто это конкретное поле, есть ли ошибки, является ли оно нетронутым, какова его ценность и все такое прочее.
Итак, скажем, у вас это так:
errors: [],
onChange: false,
pristine: true,
touched: false,
value,
Назовем это StateChangeEvent.
Теперь каждое поле ввода будет иметь обработчик таких событий, как изменение и размытие. Здесь этот отдельный компонент будет обновлять StateChangeEvent. И эти методы в конечном итоге вызовут функцию обратного вызова с StateChangeEvent в качестве аргумента.
Таким образом, родитель узнает, что в одном из полей произошло изменение, и сможет соответствующим образом отреагировать.
В родительском компоненте, чтобы активировать кнопку «Отправить» в форме, мы также можем иметь побочный эффект, который будет обновлять общее состояние формы. Что-то вроде этого:
useEffect(() => {
const isValid = !fieldOne.onChange &&
fieldOne.errors.length === 0 &&
fieldOne.value.length !== 0 &&
!fieldTwo.onChange &&
fieldTwo.errors.length === 0 &&
fieldTwo.value.length !== 0 &&
...;
setIsFormValid(isValid);
}, [fieldOne, fieldTwo, ...]);
Я уверен, что это не полное решение. Но я уверен, что это поможет вам начать.
Обновлено:
Основываясь на предоставленной вами CodeSandbox, вот что вы можете сделать, чтобы это заработало:
import ...
const useStyles = makeStyles(theme => ({ ... }));
const Apptest = props => {
const classes = useStyles();
const [isInvalid, setIsInvalid] = useState(true);
const handleStateChange = updatedState => {
console.info("updatedState: ", updatedState);
updatedState.errors.length === 0 ? setIsInvalid(false) : setIsInvalid(true);
};
return (
<Container component = "main" maxWidth = "xs">
<CssBaseline />
<div className = {classes.paper}>
<div className = {classes.mainBox}>
<form className = {classes.form} noValidate>
<Grid container spacing = {2}>
<EmailTextField onStateChange = {handleStateChange} />
</Grid>
<Button
variant = "contained"
color = "primary"
disabled = {isInvalid}
className = {classes.button}
>
Submit
</Button>
</form>
</div>
</div>
</Container>
);
};
export default Apptest;
И в компоненте EmailTextField:
import React, { useState } from "react";
import TextField from "@material-ui/core/TextField";
import Grid from "@material-ui/core/Grid";
export const EmailTextField = props => {
const { onStateChange } = props;
const [state, setState] = useState({
errors: [],
onChange: false,
pristine: true,
touched: false,
value: null
});
const helperText = "Email address will be used as your username.";
const handleBlur = event => {
// Email Validation logic
const matches = event.target.value.match(
`[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,3}`
);
if (matches) {
const updatedState = {
...state,
touched: true,
value: event.target.value,
errors: []
};
setState(updatedState);
onStateChange(updatedState);
} else {
const updatedState = {
...state,
touched: true,
value: event.target.value,
errors: ["Please enter a valid email"]
};
setState(updatedState);
onStateChange(updatedState);
}
};
return (
<Grid item xs = {12}>
<TextField
variant = "outlined"
required
fullWidth
id = "email"
label = "email address"
error = {state.errors.length > 0}
helperText = {state.errors.length > 0 ? state.errors[0] : helperText}
name = "email"
autoComplete = "email"
margin = "dense"
onBlur = {handleBlur}
/>
</Grid>
);
};
export default EmailTextField;
Я загрузил свой пример кода в codeandbox.io/embed/cranky-glade-82leu
В этом случае, как я могу получить состояние «isValid» в component/UI/testfield/EmailTextfield.js из aptest.js?
Я видел ваш ответ, но было неясно, как я буду передавать StateChangeEvent туда и обратно между компонентами.
Я разобрался, извините за поздний ответ. Я спал. По сути, onBlur() принимает обратный вызов, теперь в этом случае вам нужно передать значение в поле ввода обратному вызову, чтобы вы могли получить доступ к значению пользовательского ввода. Другой способ — использовать onChange() для отслеживания изменения и настроить его так, чтобы при вызове onblur вы могли проверить value, а затем выполнить проверки.
Таким образом, вам просто нужно передать target значение события в callback вот так onBlur = {(e) => handleOnChangeEmailAddress(e.target.value)}, и тогда вы сможете получить доступ к значению в методе. Я провел рефакторинг кода, которым вы поделились в песочнице. Найдите ниже фрагмент того, что я сделал.
import React, { useState } from "react";
import TextField from "@material-ui/core/TextField";
import Grid from "@material-ui/core/Grid";
export const EmailTextField = props => {
const [value, setValue] = useState("");
const [helperText, setHelperText] = useState(
"Email address will be used as your username."
);
const [isValid, setIsValid] = useState("true");
const handleOnChangeEmailAddress = value => {
// Email Validation logic
if (!value) {
setIsValid(true);
} else {
setIsValid(false);
}
console.info(isValid)
};
return (
<Grid item xs = {12}>
<TextField
variant = "outlined"
required
fullWidth
id = "email"
label = "email address"
error = {!isValid}
helperText = {helperText}
name = "email"
autoComplete = "email"
margin = "dense"
onBlur = {(e) => handleOnChangeEmailAddress(e.target.value)}
/>
</Grid>
);
};
export default EmailTextField;
Я надеюсь, что это поможет .. если у вас есть какие-либо проблемы, не стесняйтесь задавать вопросы ..
Из вашего примера codeandbox похоже, что вы были почти там, вам просто нужно было передать свою функцию onStateChange в качестве опоры:
<EmailTextField onStateChange = {onStateChange} />
Затем реализуйте функцию onStateChange в файле apptest.js, который получит обновленный объект.
Посмотрите мой пример ниже и откройте консоль, вы увидите журналы консоли для ошибок и ответ «isValid», если адрес электронной почты действителен.
https://codesandbox.io/s/loving-blackwell-nylpy?fontsize=14
Спасибо большое. Я следовал решению SiddAjmera (как вы и сказали), и оно работает!
не беспокойтесь @hinewwiner рад, что вы смогли заставить его работать
не могли бы вы добавить пример кода или ссылку на codeandbox?