javascript - 在 React 中处理两个相似类型的 useEffect 函数的最佳方法是什么?
问题描述
所以我在 React 中有一个表单,我有一个用户名字段和电子邮件字段。在用户停止输入 800 毫秒后,我正在检查用户名/电子邮件(基于用户正在输入的字段)是否可用(不被其他人使用)。
我最终有两个非常相似的 useEffect 函数对用户名和电子邮件执行相同的操作,只是它们发送请求的 URL 和它们正在监视的变量不同。
我在这里分享代码片段。我在这里使用 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>
正如你所看到的,这里有很多重复的代码,我想知道有没有更好的方法来处理事情。
解决方案
为什么在你的 onchanged 事件中更好地使用 useEffect 中的所有这些?
let timer = []; //this is a global variable, need to be outside your component so the value does not get reset on every render.
const MyComponent = () => {
const [ isUsernameOk, setIsUsernameOk ] = useState(false)
......
const getResponse = (url, body) => await Axios.post(
url, body,
{ cancelToken: ourRequest.token }
); //u can put everything in one line.
const onChange = () => {
const { name, value } = e.target
dispatch({ type: 'usernameImmediately', value: e.target.value })
clearTimeout(timer[name]);
timer[name] = setTimeout(dispatch({ type: 'usernameAfterDelay' }),899)
// OR
timer[name] == setTimeout(async () => {
const response = await getResponse('/emailCheck', { email: test@email.com })
//do whatever u want with response
//do your dispatch or,
setIsUsernameOk(true)
})
}
return (
...............
{ isUserNameOk && <span> Username is available </span>
)
}
无论您在做什么,都不需要使用 useEffect。不必要地使用 useEffect 是无效的,并且可能不必要地导致循环错误(以及不必要的重新渲染)
和
这是单查?你真的需要通过所有的 redux 代码来使你的组件复杂化吗?地方状态不足吗?
推荐阅读
- azure-blob-storage - Azure 存储文件的上次访问时间
- google-apps-script - 我可以在不发送通知的情况下删除 Google 日历中的一系列活动吗?
- c - 创建两个具有相同大小和相同 md5 哈希的不同二进制文件
- javascript - 在反应js中的动态菜单栏上创建路由
- delphi - TTask 运行生命周期或当他应该仍然活跃时
- python - 我试图用 python 从亚马逊上刮价格,但我得到一个 AttributeError
- python - 管理员权限检查 (aiogram)
- go - 我可以将 Elasticsearch 与需要身份验证才能查看的数据一起使用吗(例如,仅限登录用户)
- python - 试图计算浮动列表的平均值?
- asp.net - 我想添加外键,但添加时出错