Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 如何在功能组件之间传递状态?_Reactjs_State_React Hooks - Fatal编程技术网

Reactjs 如何在功能组件之间传递状态?

Reactjs 如何在功能组件之间传递状态?,reactjs,state,react-hooks,Reactjs,State,React Hooks,我目前正在用react-js和react-hooks编写一个注册页面,我还在学习,如果这是一个非常简单的问题,请原谅 我有一个signup.js,是用带有钩子的功能组件编写的。signup.js导入“EmailTextField”、“PasswordTextField”、“NameTextField”、“CellPhoneTextField”。。。其中的组件也写在带有挂钩的功能组件中 我将所有这些文本字段作为单独的组件来简化代码,因为我需要对每个文本字段进行许多不同的检查。(在signup.js

我目前正在用react-js和react-hooks编写一个注册页面,我还在学习,如果这是一个非常简单的问题,请原谅

我有一个signup.js,是用带有钩子的功能组件编写的。signup.js导入“EmailTextField”、“PasswordTextField”、“NameTextField”、“CellPhoneTextField”。。。其中的组件也写在带有挂钩的功能组件中

我将所有这些文本字段作为单独的组件来简化代码,因为我需要对每个文本字段进行许多不同的检查。(在signup.js页面中包含所有这些字段会产生很长的代码)

在signup.js的过程结束时,我想获取它的所有子组件(所有这些文本字段)的状态(用户是否愿意登录)。但是我不确定如何将这些文本字段的状态(或变量)传递给signup.js

我知道redux可以管理状态,但在没有redux的情况下是否可以实现这一点

多谢各位

我已经用最少的示例代码创建了一个

在这里,我使用
apptest.js
中的
EmailTextfield
组件。我想从
apptest.js
获取
EmailTextfield
上的
isValid
状态,以便确保在用户注册之前验证所有字段

“./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;
import React,{useState}来自“React”;
从“@material ui/core/TextField”导入TextField;
从“@material ui/core/Grid”导入网格;
export const EmailTextField=props=>{
const[value,setValue]=useState(“”);
常量[helperText,setHelperText]=useState(
“电子邮件地址将用作您的用户名。”
);
const[isValid,setIsValid]=useState(“true”);
const handleOnChangeEmailAddress=事件=>{
//电子邮件验证逻辑
如果(真){
setIsValid(true);
}否则{
setIsValid(false);
}
};
返回(
);
};
导出默认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;
从“React”导入React;
从“@material ui/core/CssBaseline”导入CssBaseline;
从“@material ui/core/Grid”导入网格;
从“@material ui/core/styles”导入{makeStyles}”;
从“@material ui/core/Container”导入容器;
从“/components/UI/Textfield/EmailTextField”导入{EmailTextField}”;
const useStyles=makeStyles(主题=>({
“@global”:{
正文:{
背景色:theme.palette.common.white
}
},
论文:{
marginTop:主题。间距(8),
显示:“flex”,
flexDirection:“列”,
对齐项目:“中心”
},
主机箱:{
//保证金:“200px”,
宽度:“550px”,
textAlign:“左”,
boxShadow:“0 2px 3px#ccc”,
边框:“1px实心#eee”,
填充:“40px 70px 50px 70px”,
框大小:“边框框”
},
表格:{
宽度:“100%,//修复IE 11问题。
marginTop:主题。间距(3)
}
}));
常量Apptest=props=>{
const classes=useStyles();
返回(
);
};
导出默认Apptest;

我想到了一个非常粗糙的实现

输入字段周围应该有一个一致的数据模型。该数据模型应该是该特定输入字段的唯一真实来源。它应该能够判断特定字段是否被触及,是否有错误,是否原始,它的价值是什么,以及所有这些

假设你有这样一个例子:

errors: [],
onChange: false,
pristine: true,
touched: false,
value,
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, ...]);
让我们称之为
StateChangeEvent

现在,每个输入字段将有一个事件处理程序,如更改和模糊。在这里,单个组件将更新StateChangeEvent。这些方法最终将以
StateChangeEvent
作为参数调用回调函数

这样,父级将知道其中一个字段发生了更改,并且可以相应地做出响应

在父组件中,为了启用表单上的Submit按钮,我们还可以产生一个副作用,它将更新表单的整体状态。大概是这样的:

errors: [],
onChange: false,
pristine: true,
touched: false,
value,
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.log("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;

这是给你的裁判的一封信


我心里有一个非常粗糙的实现

输入字段周围应该有一个一致的数据模型。该数据模型应该是该特定输入字段的唯一真实来源。它应该能够判断特定字段是否被触及,是否有错误,是否原始,它的价值是什么,以及所有这些

假设你有这样一个例子:

errors: [],
onChange: false,
pristine: true,
touched: false,
value,
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, ...]);
让我们称之为
StateChangeEvent

现在,每个输入字段将有一个事件处理程序,如更改和模糊。在这里,单个组件将更新StateChangeEvent。这些方法最终将以
StateChangeEvent
作为参数调用回调函数

这样,父级将知道其中一个字段发生了更改,并且可以相应地做出响应

在父组件中,为了启用表单上的Submit按钮,我们还可以产生一个副作用,它将更新表单的整体状态。大概是这样的:

errors: [],
onChange: false,
pristine: true,
touched: false,
value,
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.log("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;

这是给你的裁判的一封信


我想出来了,很抱歉回复晚了。我睡着了。基本上,
onBlur()
接受回调,在这种情况下,您需要将输入框中的值传递给回调,以便可以访问用户输入的值。另一种方法是使用
onChange()
跟踪更改,并将其设置为当
打开时