【问题标题】:Best way to handle two similar type of useEffect functions in React?在 React 中处理两个相似类型的 useEffect 函数的最佳方法是什么?
【发布时间】: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


    【解决方案1】:

    如何制作一个自定义挂钩来存储状态并检查电子邮件是否有效?您也可以将您的 API 调用组合成一个函数,然后将 useEffect 组合成一个函数。

    【讨论】:

      【解决方案2】:

      为什么在你的 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 代码来使你的组件复杂化吗?本地状态不足吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-21
        • 1970-01-01
        • 1970-01-01
        • 2021-11-18
        • 2015-01-19
        • 2010-09-05
        相关资源
        最近更新 更多