单击按钮时如何使用 useRef 挂钩关注 Material UI TextField?

Posted

技术标签:

【中文标题】单击按钮时如何使用 useRef 挂钩关注 Material UI TextField?【英文标题】:How to focus on Material UI TextField using useRef hooks when a button is clicked? 【发布时间】:2020-10-03 02:11:05 【问题描述】:

我遇到了与How to focus a Material UI Textfield on button click? 类似的问题,但我无法通过提供的答案解决问题。

这是代码。基本上,所有文本字段都被禁用。单击编辑配置文件按钮时,它将帐户名称的disabled 状态设置为false,我想专注于该特定字段。我正在使用 useRef 挂钩来引用该字段,但它不起作用。只有单击该按钮两次才会起作用。

import React,  useState, useEffect, useRef  from "react";
import Avatar from "@material-ui/core/Avatar";
import Button from "@material-ui/core/Button";
import CssBaseline from "@material-ui/core/CssBaseline";
import TextField from "@material-ui/core/TextField";
import Grid from "@material-ui/core/Grid";
import PermContactCalendarIcon from "@material-ui/icons/PermContactCalendar";
import Typography from "@material-ui/core/Typography";
import  makeStyles  from "@material-ui/core/styles";
import Container from "@material-ui/core/Container";
import Paper from "@material-ui/core/Paper";

const useStyles = makeStyles((theme) => (
  paper: 
    marginTop: theme.spacing(3),
    padding: theme.spacing(5),
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
  ,
  avatar: 
    margin: theme.spacing(1),
    backgroundColor: theme.palette.secondary.main,
  ,
  form: 
    width: "100%", // Fix IE 11 issue.
    marginTop: theme.spacing(3),
  ,
  submit: 
    margin: theme.spacing(3, 0, 2),
  ,
  fixedHeight: 
    height: 1000,
  ,
  button: 
    marginTop: theme.spacing(3),
    marginRight: theme.spacing(3),
  ,
));

export default function AccountPage( userdata ) 
  const classes = useStyles();

  const [accountName, setAccountName] = useState("");

  const [disabled, setDisabled] = useState(true);
  const inputRef = useRef(null);

  const handleOnChange = (e) => 
    if (e.target.name === "accountname") 
      setAccountName(e.target.value);
    
  ;

  return (
    <Container component="main">
      <CssBaseline />
      <Paper>
        <div className=classes.paper>
          <Avatar className=classes.avatar>
            <PermContactCalendarIcon />
          </Avatar>
          <Typography component="h1" variant="h5">
            Account & User Settings
          </Typography>
          <form className=classes.form noValidate>
            <Grid
              container
              direction="column"
              justify="center"
              alignItems="stretch"
              spacing=2
            >
              <Grid item xs=12>
                <Typography color="primary" display="inline" noWrap>
                  Account Name :
                </Typography>
              </Grid>
              <Grid item xs=12>
                <TextField
                  name="accountname"
                  variant="outlined"
                  fullWidth
                  //   autoFocus
                  onChange=handleOnChange
                  disabled=disabled
                  value=accountName
                  inputRef=inputRef
                />
              </Grid>
              <Grid item xs=12>
                <Typography color="primary" display="inline" noWrap>
                  E-mail Address :
                </Typography>
              </Grid>
              <Grid item xs=12>
                <TextField
                  variant="outlined"
                  fullWidth
                  value=userdata.email
                  type="email"
                  name="email"
                  disabled=true
                  //   onChange=handleOnChange
                />
              </Grid>
              <Grid item xs=12>
                <Typography color="primary" display="inline" noWrap>
                  Account ID :
                </Typography>
              </Grid>
              <Grid item xs=12>
                <TextField
                  variant="outlined"
                  fullWidth
                  name="id"
                  value=userdata._id
                  type="text"
                  disabled=true
                  //   onChange=handleOnChange
                />
              </Grid>
            </Grid>
            <Button
              variant="contained"
              color="primary"
              className=(classes.submit, classes.button)
              onClick=() => 
                setDisabled(false);
                inputRef.current.focus();
              
            >
              Edit Profile
            </Button>
            <Button
              //   type="submit"
              variant="contained"
              color="primary"
              className=(classes.submit, classes.button)
              onClick=() => 
                setDisabled(true);
              
            >
              Save Changes
            </Button>
          </form>
        </div>
      </Paper>
    </Container>
  );

【问题讨论】:

【参考方案1】:

问题出在编辑按钮的 onClick 事件处理程序中:

() => 
  setDisabled(false);
  inputRef.current.focus();
;

您应该记住setState 是异步的。这是React docs的引述:

setState 函数用于更新状态。它接受一个新的 状态值和入队组件的重新渲染。

换句话说,React 承诺你 disabled 将在未来某个时间设置为 false,但可能不会在 inputRef.current.focus() 行执行时设置。

所以你要做的就是问 React:disabled 设置为 false 时,聚焦一个元素。这就是useEffect 钩子的用途——它可以让你执行副作用。因此,与其将inputRef.current.focus() 放在setDisabled(false) 之后,不如设置一个useEffect 挂钩,如下所示:

useEffect(() => 
  if (!disabled) 
    inputRef.current.focus();
  
, [disabled]); // Only run the function if disabled changes

【讨论】:

再次感谢您的帮助!它现在可以工作,但我仍然对何时使用 useEffect 挂钩感到困惑。所以基本上,如果我们有超过 1 个函数,最好使用 useEffect 以免干扰主函数? 当由于状态改变而需要做一些动作时,你应该考虑使用useEffect。这些操作可以是获取 API、更改 document.title 或聚焦元素等。我建议阅读有关 Using the Effect Hook 的 React 文档。

以上是关于单击按钮时如何使用 useRef 挂钩关注 Material UI TextField?的主要内容,如果未能解决你的问题,请参考以下文章

“从不”类型上不存在属性“值”。在 mui 中使用 useRef 挂钩时

如何在使用redux格式按下下一个键盘按钮后如何使用useRef钩子来选择下一个TextInput

使用redux-form按下下一个键盘按钮后如何使用useRef钩子选择下一个TextInput

如何更改保存在反应组件的 useRef 对象中的按钮的 onClick 功能?

提交值时如何在 React 挂钩中使用回调函数?

如何使用 Jest 和 react-testing-library 测试 useRef?