【发布时间】:2021-03-25 09:00:34
【问题描述】:
所以我在 React 中有一个表单,我有一个用户名字段和电子邮件字段。在用户停止输入 800 毫秒后,我正在检查用户名/电子邮件(基于用户正在输入的字段)是否可用(不被其他人使用)。
我最终有两个非常相似的 useEffect 函数对用户名和电子邮件执行相同的操作,只是它们发送请求的 URL 和它们正在监视的变量不同。
我在这里分享代码的sn-p。我在这里使用 useReducer。
初始状态:
const initialState = {
username: {
value: '',
hasErrors: false,
errorMessage: '',
isUnique: false,
checkCount: 0,
},
email: {
value: '',
hasErrors: false,
errorMessage: '',
isUnique: false,
checkCount: 0,
},
submitCount: 0,
}
减速机功能:
//using immer
function myReducer(draft, action) {
switch (action.type) {
case 'usernameAfterDelay':
draft.username.checkCount++;
return;
case 'usernameUniqueResults':
if (action.value) {
draft.username.hasErrors = true;
draft.username.isUnique = false;
draft.username.message = 'That username is already taken.';
} else {
draft.username.isUnique = true;
}
return;
case 'emailAfterDelay':
draft.email.checkCount++;
return;
case 'emailUniqueResults':
if (action.value) {
draft.email.hasErrors = true;
draft.email.isUnique = false;
draft.email.message = 'That email is already being used.';
} else {
draft.email.isUnique = true;
}
return;
default:
return;
}
}
const [state, dispatch] = useImmerReducer(ourReducer, initialState);
我的 useEffect 函数非常相似
useEffect 用于应用去抖动到用户输入
useEffect(() => {
if (state.username.value) {
const delay = setTimeout(() => {
dispatch({ type: 'usernameAfterDelay' });
}, 800);
return () => clearTimeout(delay);
}
}, [state.username.value]);
useEffect(() => {
if (state.email.value) {
const delay = setTimeout(() => {
dispatch({ type: 'emailAfterDelay' });
}, 800);
return () => clearTimeout(delay);
}
}, [state.email.value]);
useEffect 用于实际进行 api 调用
useEffect(() => {
if (state.username.checkCount) {
const ourRequest = Axios.CancelToken.source();
async function fetchResults() {
try {
const response = await Axios.post(
'/doesUsernameExist',
{ username: state.username.value },
{ cancelToken: ourRequest.token }
);
dispatch({ type: 'usernameUniqueResults', value: response.data });
} catch (e) {
console.log('There was a problem or the request was cancelled.');
}
}
fetchResults();
return () => ourRequest.cancel();
}
}, [state.username.checkCount]);
useEffect(() => {
if (state.email.checkCount) {
const ourRequest = Axios.CancelToken.source();
async function fetchResults() {
try {
const response = await Axios.post(
'/doesEmailExist',
{ email: state.email.value },
{ cancelToken: ourRequest.token }
);
dispatch({ type: 'emailUniqueResults', value: response.data });
} catch (e) {
console.log('There was a problem or the request was cancelled.');
}
}
fetchResults();
return () => ourRequest.cancel();
}
}, [state.email.checkCount]);
JSX如下
<div>
<label htmlFor="username-register" className="text-muted mb-1">
<small>Username</small>
</label>
<input
id="username-register"
onChange={(e) =>
dispatch({
type: 'usernameImmediately',
value: e.target.value,
})
}
value={state.username.value}
/>
<CSSTransition
in={state.username.hasErrors}
timeout={330}
classNames="liveValidateMessage"
unmountOnExit
>
<div className="alert alert-danger small liveValidateMessage">
{state.username.message}
</div>
</CSSTransition>
<div>
<div>
<label htmlFor="email-register" className="text-muted mb-1">
<small>Email</small>
</label>
<input
id="email-register"
onChange={(e) =>
dispatch({
type: 'emailImmediately',
value: e.target.value,
})
}
/>
<CSSTransition
in={state.email.hasErrors}
timeout={330}
classNames="liveValidateMessage"
unmountOnExit
>
<div className="alert alert-danger small liveValidateMessage">
{state.email.message}
</div>
</CSSTransition>
</div>
你可以看到这里有很多重复的代码,我想知道有没有更好的方法来处理。
【问题讨论】:
标签: javascript reactjs react-redux react-hooks use-effect