modifier Grâce aux hooks, vous êtes désormais en mesure de mettre en œuvre des callbacks de cycle de vie dans un composant fonctionnel sans état. Bien que cela ne réponde pas directement à tous les points de la question, cela peut également permettre de contourner certaines des raisons pour lesquelles on voulait faire ce qui était proposé à l'origine.
modifier la réponse originale Après la discussion dans les commentaires et en y réfléchissant davantage, cette réponse est plus exploratoire et peut servir d'élément de la conversation. Mais je ne pense pas que ce soit la bonne réponse.
première réponse
Sur le site de Redux, il y a un exemple qui montre que vous n'avez pas besoin de faire à la fois mapStateToProps et mapDispatchToProps. Vous pouvez simplement tirer parti de connect
Pour les accessoires, utilisez une classe et implémentez les méthodes du cycle de vie sur le composant idiot.
Dans l'exemple, l'appel de connexion est même dans le même fichier et le composant muet n'est même pas exporté, donc pour l'utilisateur du composant c'est la même chose.
Je peux comprendre que l'on ne veuille pas faire d'appels asynchrones à partir du composant d'affichage. Je pense qu'il y a une distinction entre l'émission d'appels asynchrones à partir de là et la distribution d'une action qui, avec les thunks, déplace l'émission des appels asynchrones vers les actions (encore plus découplées du code React).
Par exemple, voici un composant d'écran d'accueil pour lequel j'aimerais effectuer une action asynchrone (comme le préchargement de ressources) lorsque le composant d'affichage se monte :
SplashContainer.js
import { connect } from 'react-redux'
import Splash from '../components/Splash'
import * as actions from '../actions'
const mapStateToProps = (state) => {
return {
// whatever you need here
}
}
const mapDispatchToProps = (dispatch) => {
return {
onMount: () => dispatch(actions.splashMount())
}
}
const SceneSplash = connect(
mapStateToProps,
mapDispatchToProps
)(Splash)
export default SceneSplash
Splash.js
import React from 'react'
class Splash extends React.Component {
render() {
return (
<div className="scene splash">
<span className="fa fa-gear fa-spin"></span>
</div>
)
}
componentDidMount() {
const { onMount } = this.props
onMount()
}
}
export default Splash
Vous pouvez voir que le dispatch se fait dans le conteneur connecté, et vous pouvez imaginer dans le fichier actions.splashMount()
nous émettons une requête http asynchrone ou faisons d'autres choses asynchrones par l'intermédiaire de thunks ou des promesses.
modifier pour clarifier
Permettez-moi d'essayer de défendre l'approche. J'ai relu la question et je ne suis pas sûr à 100 % de répondre à l'essentiel de ce qu'elle demande, mais soyez indulgent avec moi. Si je ne suis toujours pas tout à fait sur la bonne voie, je propose ci-dessous une approche modifiée qui pourrait être plus proche de la réalité.
"il doit être rempli au chargement" - l'exemple ci-dessus accomplit ceci
"Je veux lancer l'extraction asynchrone à partir d'un conteneur" - dans l'exemple, l'extraction n'est pas lancée à partir du composant d'affichage ou du conteneur, mais à partir d'une action asynchrone.
"Cela semble rendre impossible de mettre toute la logique dans le conteneur" - Je pense que vous pouvez toujours mettre toute logique supplémentaire nécessaire dans le conteneur. Comme indiqué, le code de chargement des données n'est pas dans le composant d'affichage (ou le conteneur) mais dans le créateur d'action asynchrone.
"Cela signifie que je ne peux pas utiliser un composant fonctionnel sans état pour un composant qui a besoin de données asynchrones." - Dans l'exemple ci-dessus, le composant d'affichage est apatride et fonctionnel. Le seul lien est la méthode de cycle de vie invoquant un callback. Il n'a pas besoin de savoir ou de se soucier de ce que fait cette callback. Il ne s'agit pas pour le composant d'affichage d'essayer d'être le propriétaire de la récupération de données asynchrones - il fait simplement savoir au code qui s'en occupe quand une chose particulière s'est produite.
Jusqu'à présent, j'essaie de justifier comment l'exemple donné répond aux exigences de la question. Cela dit, si ce que vous recherchez est d'avoir un composant d'affichage qui ne contient absolument aucun code lié au chargement asynchrone des données, même par des callbacks indirects - c'est-à-dire que le seul lien qu'il a est de consommer ces données via les props qui lui sont remis lorsque ces données distantes arrivent, alors je suggérerais quelque chose comme ceci :
SplashContainer.js
import { connect } from 'react-redux'
import Splash from '../components/Splash'
import * as actions from '../actions'
const mapStateToProps = (state) => {
return {
// whatever you need here
}
}
const mapDispatchToProps = (dispatch) => {
dispatch(actions.splashMount())
return {
// whatever else here may be needed
}
}
const SceneSplash = connect(
mapStateToProps,
mapDispatchToProps
)(Splash)
export default SceneSplash
Splash.js
import React from 'react'
class Splash extends React.Component {
// incorporate any this.props references here as desired
render() {
return (
<div className="scene splash">
<span className="fa fa-gear fa-spin"></span>
</div>
)
}
}
export default Splash
En répartissant l'action dans mapDispatchToProps, vous laissez le code de cette action résider entièrement dans le conteneur. En fait, vous lancez l'appel asynchrone dès que le conteneur est instancié, plutôt que d'attendre que le composant d'affichage connecté tourne et soit monté. Cependant, si vous ne pouvez pas commencer l'appel asynchrone avant que le componentDidMount() du composant d'affichage ne se déclenche, je pense que vous êtes intrinsèquement lié à un code comme dans mon premier exemple.
Je n'ai pas encore testé cette deuxième approche pour voir si react ou redux s'en plaindront, mais cela devrait fonctionner. Vous avez accès à la méthode dispatch et devriez pouvoir l'appeler sans problème.
Pour être honnête, ce deuxième exemple, tout en supprimant tout le code lié à l'action asynchrone du composant d'affichage, me semble un peu étrange puisque nous faisons des choses qui ne sont pas liées à l'action asynchrone dans la fonction éponyme. Et les conteneurs n'ont pas vraiment de componentDidMount pour l'exécuter autrement. Donc je suis un peu nerveux avec ça et je pencherais pour la première approche. Ce n'est pas propre dans le sens "se sentir bien", mais ça l'est dans le sens "simple 1-liner".