使用 ref: reference 可以在最终呈现的 HTML 元素和其他 JavaScript 代码之间建立连接。
如下的代码,需要获取表单的 input 输入,一种方法是使用 useState()
,一个 input 一个 state,每次键盘按一个键,state 就更新一次。
但是,因为需要的只是最终结果,如果不需要每按一次键就验证一下输入是否合法的话,这种做法就显得冗余。这时可以使用 useRef
钩子函数:
首先 import useRef
:
import React, { useState, useRef } from "react";
然后,调用钩子函数,生成两个ref 对象,这里的对象有一个 current
属性,保存着所连接的元素的实际值。
const nameInputRef = useRef(); // undefined
const ageInputRef = useRef(); // undefined
然后,需要连接的元素加 ref
属性,此属性和 key
一样,是默认HTML 属性:
<input id="username" type="text" ref={nameInputRef} />
<input id="age" type="number" ref={ageInputRef} >
于是两个对象和 input 分别建立起连接,获取 input 的值的方法:
const enteredName = nameInputRef.current.value;
const enteredUserAge = ageInputRef.current.value;
表单提交后,重置 input 元素,清空表单:
nameInputRef.current.value = "";
ageInputRef.current.value = "";
理论上可以通过ref 对象操纵DOM,但是实际上操纵 DOM 这种事情应该留给 React 去做,所以要尽可能避免。上面重置 input 的做法属于 edge case ,毕竟并没有增加或者删除HTML元素,或者修改 css style 之类,只是重设了一下input 的值,所以是ok的。
总之,这种情况下使用 useRef
比起使用 useState
代码更为简洁。但使用 useState
也是完全没有问题的。
完整的代码如下:
import React, { useState, useRef } from "react";
import Button from "../UI/Button";
import classes from "./AddUser.module.css";
const AddUser = (props) => {
const nameInputRef = useRef(); // undefined !
const ageInputRef = useRef(); // undefined !
const [error, setError] = useState();
const addUserHandler = (event) => {
event.preventDefault();
const enteredName = nameInputRef.current.value;
const enteredUserAge = ageInputRef.current.value;
if (enteredName.trim().length === 0 || enteredUserAge.trim().length === 0) {
setError({
title: "Invalid input",
message: "Please enter a valid name and age (non-empty values).",
});
return;
}
if (+enteredUserAge < 1) {
setError({
title: "Invalid age",
message: "Please enter a valid age (> 0).",
});
return;
}
props.onAddUser(enteredName, enteredUserAge);
nameInputRef.current.value = "";
ageInputRef.current.value = "";
};
const errorHandler = () => {
setError(null);
};
return (
<div>
<form onSubmit={addUserHandler}>
<label htmlFor="username">Username</label>
<input id="username" type="text" ref={nameInputRef} />
<label htmlFor="age">Age (Years)</label>
<input id="age" type="number" ref={ageInputRef} />
<Button type="submit">Add User</Button>
</form>
</div>
);
};
export default AddUser;
More Example:
import { useRef, useState } from "react";
const SimpleInput = (props) => {
const nameInputRef = useRef();
const [enteredName, setEnteredName] = useState("");
const nameInputChangeHandler = (event) => {
setEnteredName(event.target.value);
console.log(enteredName);
};
const formSubmissionHandler = (event) => {
event.preventDefault();
console.log(enteredName);
const enteredValue = nameInputRef.current.value;
console.log(enteredValue);
setEnteredName("");
};
return (
<form onSubmit={formSubmissionHandler}>
<div className="form-control">
<label htmlFor="name">Your Name</label>
<input
ref={nameInputRef}
type="text"
id="name"
onChange={nameInputChangeHandler}
value={enteredName}
/>
</div>
<div className="form-actions">
<button>Submit</button>
</div>
</form>
);
};
export default SimpleInput;