web-dev-qa-db-fra.com

Pouvez-vous revenir tôt avec des crochets React?

Les documents React expliquent clairement que appeler des hooks conditionnellement ne fonctionnera pas . à partir de la présentation originale React hooks) , la raison en est que React utilise l'ordre que vous appelez hooks pour injecter la valeur correcte.

Je comprends cela, mais maintenant ma question est de savoir s'il est correct de revenir tôt à partir d'un composant de fonction avec des crochets.

Est-ce que quelque chose comme ça est autorisé?:

import React from 'react';
import { useRouteMatch, Redirect } from 'react-router';
import { useSelector } from 'react-redux';

export default function Component() {
  const { match } = useRouteMatch({ path: '/:some/:thing' });
  if (!match) return <Redirect to="/" />;

  const { some, thing } = match.params;
  const state = useSelector(stateSelector(some, thing));

  return <Blah {...state} />;
}

Techniquement, le hook useSelector est appelé de manière conditionnelle, mais l'ordre lors de leur appel ne change pas entre les rendus (même s'il est possible qu'un hook de moins soit appelé).

Si cela n'est pas autorisé, pouvez-vous expliquer pourquoi cela n'est pas autorisé et fournir des approches alternatives générales au retour précoce d'un composant de fonction avec des crochets?

21
Rico Kahler

Comme mentionné, vous ne pouvez pas exécuter les hooks conditionnellement à l'intérieur du composant. Mais vous pouvez transmettre la fonction de rendu qui pourrait être considérée comme un crochet personnalisé à d'autres composants et avoir toujours accès à la portée actuelle. Donc, au lieu de diviser votre composant, utilisez un composant utilitaire comme celui-ci:

import React from "react";
import ReactDOM from "react-dom";

const HooksHost = ({ children }) => children();

function App() {
  const [state1, setState1] = React.useState(1);

  if (state1 === 3) {
    return <div>State 1 is 3</div>;
  }

  return (
    <HooksHost>
      {/* should be named to pass lint rule that checks if it starts from 'use' then it is custom hook */}
      {function useHooks() {
        const [state2, setState2] = React.useState(2);
        return (
          <div className="App">
            <div>State 1: {state1}</div>
            <div>State 2: {state2}</div>
            <button onClick={() => setState1(state1 + 1)}>
              Increment State 1
            </button>
            <button onClick={() => setState2(state2 + 1)}>
              Increment State 2
            </button>
          </div>
        );
      }}
    </HooksHost>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
0
Ivanov Ivan