useEffect - предотвратить ненужное выполнение

У меня есть метод async redux-thunk, который выполняет процесс проверки на стороне сервера и обновляет мое глобальное значение состояния response-redux - hasServerError соответственно из Ответ REST, чтобы поймать обновленное значение из состояния response-redux, я использую здесь метод useEffect, например

const hasServerError = useSelector(state => return state.hasServerError );
const dispatch = useDispatch();
const saveButtonClick = () => {
   // validateForm is a redux-thunk method that will send form data to server through REST
   // and update `hasServerError ` to be true if there is error from server response
   dispatch(validateForm());     
}

// when the above validateForm would updated the value of `hasServerError `, this should trigger
useEffect(() => {
   // if hasServerError still false, continue saveFormData
   // otherwise, display a error modal
   if (!hasServerError) {
      dispatch(saveForm());     
   } else {
      dispatch(showErrorModal());
   }
}, [hasServerError, dispatch])

Это будет хорошо работать, когда пользователь нажимает кнопку сохранения, однако что-то вело себя странно, что когда hasServerError было установлено значение false из другой отправки, и saveForm снова запускался автоматически, например, когда я загружаю свой данные формы изначально, или когда пользователь исправляет свою ошибку в форме или пользователь нажимает кнопку отмены, и мне нужно запустить метод, который автоматически сбрасывает глобальное состояние hasServerError на false, когда происходит такой сценарий, мой useEffect автоматически запускается с saveForm, например:

const textInputChange = (e) {
    if (forceSave) {
       dispatch(clearHasServerError());     // set state `hasServerError` to false, but it triggered the useEffect
    }
}

or

const cancelButtonClick = () => {
   dispatch(clearHasServerError());     // set state `hasServerError` to false, but it triggered the useEffect
}

Я понимаю, что это произошло из-за того, что моя зависимость hasServerError обновилась, но как я могу позволить своему useEffect выполнять saveForm только тогда, когда пользователь нажимает кнопку, но не тогда, когда в любое время значение состояния hasServerError становится ложным?

Должен ли я установить другой флаг, когда пользователь нажимает кнопку, и добавлять его в useEffect как побочное условие if? Это кажется неразумным подходом, но пока я не могу придумать лучшего решения ...


person KevDing    schedule 10.08.2020    source источник
comment
Как насчет проверки event объекта внутри saveForm? event должен существовать только при нажатии кнопки.   -  person bertdida    schedule 10.08.2020
comment
saveForm был внешним методом redux-thunk, я не обнаружил, что там есть объект event ... что делает saveForm, так это извлекает из некоторого глобального состояния редукции данных и выполняет PUT запрос api к серверу, это не включить любой элемент dom ..   -  person KevDing    schedule 10.08.2020
comment
Да, вам нужно добавить локальный флаг, указывающий, что нажата кнопка сохранения. а затем эффект внутреннего использования, вы можете проверить это.   -  person Sagar Darekar    schedule 10.08.2020
comment
Да, @SagarDarekar, это мое временное решение, я как-то чувствую, что это ugly подход ...   -  person KevDing    schedule 11.08.2020


Ответы (1)


как я мог позволить своему useEffect выполнять saveForm только тогда, когда пользователь нажимает кнопку

Если вы хотите, чтобы saveForm выполнялся при нажатии кнопки, просто добавьте его в обработчик нажатия кнопки. Если вы хотите проверять обновления состояния, проверяйте его, когда значение изменяется в вашем редукторе. В основном,

case "SET_SOME_VALUE": {
    return {
        ...state,
        someValue: action.payload,
        isValid: validate(state)
    }
}

или сделайте это прямо в компоненте,

const component = props => {
    const state = useSelector(getState)
    const isValid = validator(state)

    const handleSave = () => { /* save stuff */ }

    /* do something with the validation */
    return <div className={isValid ? 'validCss' : 'invalidCss'}>Hello World</div>
}

Сделайте изменение состояния кнопки, а затем запустив useEffect побочный эффект, основанный на этом изменении состояния, можно получить немного волос при повторном рендеринге. Если вы можете сделать это в обработчике кликов, это, вероятно, лучше всего.

person Yatrix    schedule 10.08.2020
comment
Привет, @Yatrix, спасибо, что поделились своей идеей! Это будет работать в основном для client side проверки, однако моя validateForm - это проверка на стороне службы, которая будет публиковать formData через REST в redux-thunk, поэтому я вызываю свой redux-thunk dispatch(validateForm()); нажатием кнопки - handleSave, и я должен использовать useEffect для отслеживания состояния hasError значения, так как оно будет обновляться в преобразователе redux на основе моего ответа сервера. - person KevDing; 11.08.2020