Использование хуков + обратные вызовы - PullRequest
0 голосов
/ 27 октября 2019

В настоящее время я конвертирую этот шаблон с открытым исходным кодом ( React + Firebase + Material UI ). Если вы заглянете во многие части кодовой базы, то заметите, что после изменения переменной состояния будет обратный вызов. Вот один пример из метода signUp, найденного в SignUpDialog.js file:

signUp = () => {
const {
  firstName,
  lastName,
  username,
  emailAddress,
  emailAddressConfirmation,
  password,
  passwordConfirmation
} = this.state;

const errors = validate({
  firstName: firstName,
  lastName: lastName,
  username: username,
  emailAddress: emailAddress,
  emailAddressConfirmation: emailAddressConfirmation,
  password: password,
  passwordConfirmation: passwordConfirmation
}, {
  firstName: constraints.firstName,
  lastName: constraints.lastName,
  username: constraints.username,
  emailAddress: constraints.emailAddress,
  emailAddressConfirmation: constraints.emailAddressConfirmation,
  password: constraints.password,
  passwordConfirmation: constraints.passwordConfirmation
});

if (errors) {
  this.setState({
    errors: errors
  });
} else {
  this.setState({
    performingAction: true,

    errors: null
  }, () => {        //!HERE IS WHERE I AM CONFUSED
    authentication.signUp({
      firstName: firstName,
      lastName: lastName,
      username: username,
      emailAddress: emailAddress,
      password: password
    }).then((value) => {
      this.props.dialogProps.onClose();
    }).catch((reason) => {
      const code = reason.code;
      const message = reason.message;

      switch (code) {
        case 'auth/email-already-in-use':
        case 'auth/invalid-email':
        case 'auth/operation-not-allowed':
        case 'auth/weak-password':
          this.props.openSnackbar(message);
          return;

        default:
          this.props.openSnackbar(message);
          return;
      }
    }).finally(() => {
      this.setState({
        performingAction: false
      });
    });
  });
}

};

С хуками я попробовал что-то подобное в выражении else...

setPerformingAction(true)
setErrors(null), () => {...}

Я буду честен, я не самый лучший в обратных вызовах. Из того, что я думаю, это то, что вызывает следующие методы после того, как состояние было установлено. Тем не менее, по словам Эслинта, это неправильно, и я надеялся увидеть, сможет ли кто-нибудь помочь. Спасибо, Бреннан.

Ответы [ 3 ]

1 голос
/ 27 октября 2019

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

Мышление в функциональных компонентах - это другоеигра в мяч, а не мышление в компонентах, основанных на классах. Проще всего сказать, что компоненты, основанные на классах, являются более императивными, а хуки / функциональные компоненты - более декларативными.

Для ловушки useEffect требуется массив зависимостей (часть в конце }, [clicks]) является массивом зависимостей) - каждый раз, когда переменная, включенная в массив зависимостей, изменяется,useEffect метод запущен.

Это означает, что вы можете использовать useEffect аналогично обратному вызову setState. Хуки позволяют вам сосредоточиться и иметь детальный контроль надочень специфические части вашего состояния.

Этот является хорошим потоком для проверки - и, более конкретно, хорошим объяснением различия между основанным на классе (setState) и основанным на хуках(useState) парадигмы.

В следующем примере показано, как добиться чего-то похожего на поведение «обратного вызова», но с использованием хуков / функциональных компонентов.

const { render } = ReactDOM;
const { Component, useState, useEffect } = React;

/**
 * Class based with setState
 */
class MyClass extends Component {
  state = {
    clicks: 0,
    message: ""
  }

  checkClicks = () => {
    let m = this.state.clicks >= 5  ? "Button has been clicked at least 5 times!" : "";
    this.setState({ message: m });
  }

  handleIncrease = event => {
    this.setState({
      clicks: this.state.clicks + 1
    }, () => this.checkClicks());
  }
  
  handleDecrease = event => {
    this.setState({
      clicks: this.state.clicks - 1
    }, () => this.checkClicks());
  }
  
  render() {
    const { clicks, message } = this.state;
    
    return(
      <div>
        <h3>MyClass</h3>
        <p>Click 'Increase' 5 times</p>
        <button onClick={this.handleIncrease}>Increase</button>
        <button onClick={this.handleDecrease}>Decrease</button>
        <p><b><i>MyClass clicks:</i></b> {clicks}</p>
        <p>{message}</p>
      </div>
    );
  }
}


/**
 * Function based with useState and useEffect
 */
function MyFunction() {
  const [clicks, setClicks] = useState(0);
  const [message, setMessage] = useState("");
  
  useEffect(() => {
    let m = clicks >= 5 ? "Button has been clicked at least 5 times!" : "";
    setMessage(m);
  }, [clicks]);
  
  const handleIncrease = event => setClicks(clicks + 1);
  const handleDecrease = event => setClicks(clicks - 1);
  
  return(
    <div>
      <h3>MyFunction</h3>
      <p>Click 'Increase' 5 times</p>
      <button onClick={handleIncrease}>Increase</button>
      <button onClick={handleDecrease}>Decrease</button>
      <p><b><i>MyFunction clicks:</i></b> {clicks}</p>
      <p>{message}</p>
    </div> 
  );
}


function App() {
  return(
    <div>
      <MyClass />
      <hr />
      <MyFunction />
    </div>
  );
}


render(<App />, document.body);
p {
  margin: 1px;
}

h3 {
  margin-bottom: 2px;
}

h3 {
  margin-top: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
0 голосов
/ 27 октября 2019

В этом случае, если вы хотите запустить некоторую функцию обратного вызова, если после выполнения действия возникнут какие-либо ошибки, вы можете использовать useEffect в этом случае, так как обработчики реагирования не принимают вторую необязательную функцию обратного вызова, как с setState.

вы можете добавить ошибки в массив зависимостей useEffect и написать функцию обратного вызова внутри useEffect. Что потенциально означает выполнение некоторой функции в случае ошибок.

performAnAction = () => {

   if (actionWentWrong) {
     setError();  // maintained in state using useState  ( const [error, setError] = useState(false);
   }

}

useEffect(() => {

   // inside of this function if there are any errors do something
   if(error) {
     // do something which you were previously doing in callback function
   }
}, [error]); // this useEffect is watching if there is any change to this error state
0 голосов
/ 27 октября 2019

Вы можете использовать установщик useState несколько раз в обработчике, но вы должны передать функцию установщику вместо простой ее установки.

Это также решает отсутствующую зависимость, если вы создаетеваш обработчик с помощью useEffect.

const [state, setState] = useState({ a: 1, b: 2 });
const someHandler = useCallback(
  () => {
    //using callback method also has the linter
    //  stop complaining missing state dependency
    setState(currentState => ({ ...currentState, a: currentState.a + 1 }));
    someAsync.then(result =>
      setState(currentState => ({
        ...currentState,
        b: currentState.a * currentState.b,
      }))
    );
  },
  //if I would do setState({ ...state, a: state.a + 1 });
  //  then the next line would need [state] because the function
  //  has a dependency on the state variable. That would cause
  //  someHandler to be re created every time state changed
  //  and can make useCallback quite pointless
  [] //state dependency not needed
);

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

В прошлый раз, когда я говорил вам, что проверка смонтированного не имеет смысла, потому что вы проверяли его в компоненте приложения, и этот компонент никогда не отключается (если только вы не можете показать мне место в своем коде, которое отключает его)) но этот компонент выглядит как нечто, что может в какой-то момент размонтироваться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...