Il n'y a pas de nouveaux concepts, tous sont anciens.
Pourquoi dva ?
Après une période d'auto-apprentissage ou de formation, chacun devrait être capable de comprendre le concept de redux et de reconnaître que ce contrôle du flux de données peut rendre l'application plus contrôlable et la logique plus claire.
Mais alors, il y a généralement une telle question : il y a trop de concepts, et le réducteur, la saga et l'action sont tous séparés (sous-fichiers).
Le problème avec ceci est:
Et quelques autres :
Et dva est utilisé pour résoudre ces problèmes.
dva est un package léger basé sur l'architecture applicative existante (redux + react-router + redux-saga, etc.), sans introduire de nouveaux concepts, et le code total est inférieur à 100 lignes. (Inspiré par l'orme et le choo.)
dva est un framework, pas une bibliothèque. Semblable à emberjs, il vous indiquera clairement comment chaque composant doit être écrit, ce qui est plus contrôlable pour l'équipe. De plus, dva encapsule toutes les autres dépendances à l'exception de react et react-dom qui sont peerDependencies.
Dans l'implémentation de dva, essayez de ne pas créer une nouvelle syntaxe, mais utilisez la syntaxe de la bibliothèque de dépendances elle-même, telle que la définition du routeur ou la syntaxe JSX de react-router (la configuration dynamique est une considération de performance, qui sera prise en charge plus tard).
Le cœur de celui-ci est de fournir la méthode app.model
, qui est utilisée pour encapsuler le réducteur, l'état initial, l'action et la saga ensemble, comme :
app.model({
namespace: 'products',
state: {
list: [],
loading: false,
},
subscriptions: [
function(dispatch) {
dispatch({type: 'products/query'});
},
],
effects: {
['products/query']: function*() {
yield call(delay(800));
yield put({
type: 'products/query/success',
payload: ['ant-tool', 'roof'],
});
},
},
reducers: {
['products/query'](state) {
return { ...state, loading: true, };
},
['products/query/success'](state, { payload }) {
return { ...state, loading: false, list: payload };
},
},
});
Avant dva, nous créions normalement sagas/products.js
, reducers/products.js
et actions/products.js
puis basculions entre ces fichiers.
Présentez les clés de ces modèles : (en supposant que vous êtes déjà familiarisé avec l'architecture d'application de redux, redux-saga)
Reportez-vous aux exemples :
devtool
support d'échange à chaudSupport au niveau de l'outil de développement ?
Outre le remplacement à chaud, qui doit encore être adapté, d'autres tels que redux-devtool, css livereload, etc. sont tous compatibles.
Est-il déjà disponible pour l'environnement de construction ?
Pouvez.
Inclut-il toutes les fonctionnalités de l'architecture d'application précédente redux + redux-saga ?
Oui.
Compatibilité navigateur ?
IE8 ne le supporte pas car redux-saga est utilisé. (Nous envisagerons de prendre en charge les thunks, les promesses, les observables, etc. dans la couche d'effets de manière étendue plus tard)
Être rendu vivant par redux est tout simplement l'évangile. C'est trop simple et élégant. Grand éloge ! ! !
au fait, j'ai accidentellement vu un étranger le republier sur Twitter aujourd'hui, je pensais qu'il avait été écrit par un étranger, mais je ne m'attendais pas à ce que ce soit un camarade de classe d'Alipay, 👍
Dans l'attente de l'expansion des effets
L'environnement de production Alipay utilise-t-il cette architecture ?
@besteric dva vient de sortir et n'a pas encore été appliqué, mais l' architecture d'application sous-jacente est utilisée depuis un certain temps.
Le réducteur peut-il s'écrire ainsi :
const reducer = (state, { type, payload }) => {
switch (type) {
case 'products/query':
return { ...state, loading: true, };
case 'products/query/success':
return { ...state, loading: false, list: payload };
default
return state;
}
}
app.model({
reducer
})
Cela permet d'appliquer certaines méthodes d'ordre supérieur au réducteur.
Louange, j'ai écrit quelques démos et il n'y a qu'un seul problème, le modèle ne peut être utilisé
app.model(Model1);
app.model(Model2);
Est-ce que cette méthode complète la combinaison, en fait, je pense que l'idéal est
app.model([Model1,Model2])
un certain type de
Il est trop gênant de transmettre la répartition entre les composants, envisagez la solution suivante
Ne pas utiliser bindActionCreators
?
Le scénario spécifique de l'utilisation avancée du réducteur @yesmeck est -il uniquement redo/undo
? Je ne veux pas que dva soit trop flexible, et j'envisagerai de l'ajouter via un module complémentaire à l'avenir.
Nous en utilisons beaucoup dans notre projet. Par exemple, nous allons extraire les parties similaires de plusieurs réducteurs dans une méthode de haut niveau pour modifier le réducteur d'origine, et il existe des méthodes de haut niveau qui permettent au réducteur de réinitialiser l'état lorsque la route changements. , et ce https://github.com/erikras/multireducer
@ Tinker404 Je pense qu'il serait plus clair de déclarer le modèle séparément et qu'il serait plus facile d'ajouter et de supprimer. J'écrirais ceci :
app.model(require('../models/a'));
app.model(require('../models/b'));
@JimmyLv préfère personnellement ne pas utiliser actionCreator, mais juste dispatch
.
@yesmeck ok, je vais y repenser.
Il existe également des méthodes d'ordre supérieur qui permettent au réducteur de réinitialiser l'état lorsque l'itinéraire change
Je pense que ce scénario est plus approprié en souscrivant aux changements de routage dans subscriptions
, puis en réinitialisant l'état par l'action. Ou y a-t-il un avantage à utiliser la méthode du réducteur-amplificateur ?
Je pense que ce scénario est plus approprié en souscrivant aux changements de routage dans les abonnements, puis en réinitialisant l'état par l'action
Dans ce cas, chaque réducteur qui doit être réinitialisé doit écrire la logique de réinitialisation. Si nous utilisons une méthode de haut niveau, nous n'avons qu'à le faire maintenant :
combineReducers({
products: composeReducers({ // composeReducers 的实现见下面
recycle(LOCATION_CHANGE, initialState), // recycle 用来在路由变化时重置状态
products
})
})
Un autre scénario est la même logique dont je parle pour extraire différents réducteurs. Par exemple, il y a une liste de produits et une liste d'utilisateurs, et leurs réducteurs sont comme ceci :
// reducers/products.js
const reducer = (state, { type, action}) => {
switch (type) {
case 'products/FETCH_SUCCESS':
return {
...state,
loading: false,
list: payload
}
default:
return state
}
}
// reducers/users.js
const reducer = (state, { type, payload}) => {
switch (type) {
case 'users/FETCH_SUCCESS':
return {
...state,
loading: false,
list: payload
}
default:
return state
}
}
Ici, les deux réducteurs sont presque identiques, donc nous les extrayons et écrivons un réducteur de liste :
const list = (actionType) => {
return (state, { type, payload }) => {
switch (type) {
case actionType:
return {
...state,
loading: false,
list: payload
}
break;
default:
return state
}
}
}
Ensuite, nous implémentons un composeReducers
pour combiner ces 3 réducteurs :
function composeReducers(...reducers) {
return (state, action) => {
if (reducers.length === 0) {
return state
}
const last = reducers[reducers.length - 1]
const rest = reducers.slice(0, -1)
return rest.reduceRight((enhanced, reducer) => reducer(enhanced, action), last(state, action))
}
}
De cette manière, le réducteur pour la liste des produits et la liste des utilisateurs devient ceci :
// reducers/products.js
const reducer = (state, { type, payload}) => {
// 其他逻辑
}
export default composeReducer(reducer, list('products/FETCH_SUCCESS'))
// reducers/users.js
const reducer = (state, { type, payload}) => {
// 其他逻辑
}
export default composeReducer(reducer, list('users/FETCH_SUCCESS'))
list n'est qu'un exemple, en fait, il existe de nombreux réducteurs dans le projet qui ont la même logique.
@yesmeck 👍, le rôle de réducteur amplificateur a été sous-estimé auparavant.
@sorrycc pouvez-vous dire pourquoi ? Appelé explicitement avec une comparaison dispatch
?
@ Tinker404 Je pense qu'il serait plus clair de déclarer le modèle séparément et qu'il serait plus facile d'ajouter et de supprimer. J'écrirais ceci :
app.model(require('../models/a'));
app.model(require('../models/b'));
Je suggère également une méthode qui peut passer dans plusieurs modèles à la fois. Les grands projets peuvent avoir de nombreux modèles. J'ai maintenant besoin (importer) de tous, puis modéliser chaque modèle un par un, ce qui n'est pas très pratique. Ma méthode actuelle d'écriture est :
// models是个文件夹,有很多model
import models from './models';
models.forEach((m)=>{
app.model(m);
});
// models.js
const context = require.context('./', false, /\.js$/);
const keys = context.keys().filter(item => item !== './index.js');
const models = [];
for (let i = 0; i < keys.length; i++) {
models.push(context(keys[i]));
}
export default models;
C'est très D.VA.
J'ai trouvé l'utilisation du composant de formulaire antd dans le tableau de bord utilisateur.Je me souviens qu'il ne peut pas être utilisé pour un composant pur.Est-ce possible maintenant ?
@codering Je ne me souviens pas qu'il y ait des restrictions, les problèmes avec antd peuvent être posés sur https://github.com/ant-design/ant-design/issues .
https://github.com/react-component/form/blob/master/README.md
C'est écrit dans la NOTE.
Bonjour, je souhaite utiliser votre dva. Actuellement, j'utilise la structure de répertoires générée par l'échafaudage React Webpack Redux. J'ai modifié le code en référence à l'exemple de tableau de bord utilisateur dans votre exemple, mais il n'y a rien après le démarrage. Pouvez-vous aider moi savoir où il est? Quelque chose s'est mal passé, mon adresse de projet: https://github.com/baiyulong/lenovo_parts
@baiyulong pourquoi ne pas le faire directement en fonction de la structure de répertoires du tableau de bord utilisateur ?
@sorrycc J'utilise maintenant la structure de répertoires du tableau de bord utilisateur.Y a-t-il un traitement spécial ou une écriture pour le routage dva?
export default function({ history }) {
return (
<Router history={history}>
<IndexRoute component={HomePage} />
<Route path='/' component={HomePage}>
<Route path='/create' component={CreateOrder} />
</Route>
</Router>
)
}
Cette route que j'ai écrite, HomePage peut, j'ai écrit un lien <Link to='/create'>Create</Link>
, je ne peux pas accéder au composant CreateOrder après avoir cliqué dessus
Il n'y a pas de manière spéciale d'écrire l'itinéraire de @baiyulong dva , veuillez essayer :
@nikogu merci beaucoup, j'irai bien après avoir sorti le nid
Bonjour, dva peut-il prendre en charge le chargement à chaud de modèles ?
@kkkf1190 envisage cela et le soutiendra.
👍
Je voulais juste vous dire merci. . .
J'ai toujours pensé que l'échafaudage de vue-cli de vuejs était très bon. Après avoir lu ceci, ma pensée a complètement changé.
Cadre très magnifique ! Recherche depuis un moment. @sorrycc Je veux poser deux questions à Yunda :
@freemember007
@sorrycc Existe-t-il maintenant une solution pour la prise en charge des réducteurs d'ordre supérieur? Notre projet utilise beaucoup de réducteurs d'ordre élevé en raison de la réutilisation
Pris en charge par @ancheel , peut être global ou local, cas d'utilisation de référence : https://github.com/dvajs/dva/blob/master/test/reducers-test.js
Une fois l'état du modèle modifié, comment le modifier à nouveau, ce problème se produit toujours maintenant
antd.js:32924 Avertissement : setState(...) : impossible de mettre à jour pendant une transition d'état existante (par exemple, dans render
ou dans le constructeur d'un autre composant). Les méthodes de rendu doivent être une fonction pure des accessoires et de l'état ; constructeur les effets secondaires sont un anti-modèle, mais peuvent être déplacés vers componentWillMount
.
Très excitant, essayez de l'utiliser dans l'environnement de production, espérons continuer à optimiser et à améliorer
nerf ça !
Bon travail 。Merci !!
@sorrycc Au plaisir de prendre en charge le rendu côté serveur !
Pris en charge par @mountainmoon , reportez-vous à https://github.com/sorrycc/dva-boilerplate-isomorphic .
Une vague de roues est arrivée :+1:
Bonjour, je viens de prendre contact avec l'apprentissage de ce dva. Après avoir lu le code pendant quelques jours, j'ai quelques questions dans mon cœur. Je voudrais demander :
J'ai vu que vos démos sont toutes des applications d'une seule page, mais ce sont toutes des applications multipages en développement. Je voudrais demander, si le routage n'est pas utilisé dans le développement d'applications multipages, comment charger des composants à la place, peut-être que je suis demander à un idiot. C'est un peu déroutant, car je n'utilise pas de routage, donc l'écouteur défini dans les modèles ne sait pas où déclencher :
histoire.écouter( emplacement => {
if(location.pathname === '/users') {
envoi({
tapez:'querySuccess',
charge utile:{}
})
}
})
PS : lors du chargement des données dans la méthode querySuccess et de l'utilisation de l'exportation par défaut connect(mapStateToProps)(Users) ; une erreur est également signalée :
connect.js:41 Uncaught TypeError : Impossible d'appeler une classe en tant que fonction
Je me sens comme un idiot en un instant, je ne sais pas si je peux te déranger pour me l'expliquer, merci !
Pourquoi dva ? en anglais s'il vous plaît
Je n'aime pas trop cette façon d'écrire.
@codering vous avez mentionné l'utilisation de composants de formulaire antd dans le tableau de bord utilisateur. Je me souviens qu'il ne peut pas être utilisé pour des composants purs. Est-ce possible maintenant ?
Je l'ai également rencontré le plus.S'il s'agit d'un composant de fonction pure, la fonction getFieldDecorator ne peut pas être obtenue via props.form.getFieldDecorator.Si vous utilisez des extensions pour créer un composant, vous pouvez l'obtenir.
Je ne sais pas si Dieu a une solution @sorrycc
Pouvez-vous s'il vous plaît lancer la même page en anglais ? Nous ne sommes pas en mesure de comprendre cela, et pourquoi avons-nous besoin de dva.
Bonjour, s'il s'agit d'un gros projet, son état sera très volumineux, et il sera très lourd à traiter, faut-il le scinder en plusieurs modèles ?
@yazhou-zyz j'ai le même problème que toi :
Avertissement : setState(...) : impossible de mettre à jour pendant une transition d'état existante (comme dans le rendu ou le constructeur d'un autre composant). Les méthodes de rendu doivent être une pure fonction des accessoires et de l'état ; les effets secondaires du constructeur sont un anti-modèle, mais peut être déplacé vers componentWillMount.
Je voudrais vous demander comment vous l'avez résolu?
Apprendre
continue d'étudier
dva est une grande valeur de référence pour les projets de construction.
bon travail ~
Où puis-je trouver les docs en anglais ??? Traduire le sujet avec des moteurs de traduction est problématique et la compréhension n'est pas suffisante. Avec l'anglais, vous pouvez atteindre le monde. Continuez votre bon travail !! :fusée:
dva n'est pas essayé dans les versions React-native 0.47.X et React16.0.0
@vecold a toujours pu l'utiliser, en disant que le code d'invitation ou le message d'erreur ne peut pas être utilisé
Y a-t-il une chance que nous puissions obtenir une traduction en anglais des documents ?
Merci!
Dans le code métier, un tel exemple est courant. Une mise à jour locale de l'état peut affecter tout le corps. De nombreux endroits qui n'ont pas besoin d'être re-rendus sont également re-rendus, ce qui réduit considérablement les performances de la page. Cette fonction peut-elle être ajoutée pour analyser automatiquement l'état dont dépend la connexion redux afin de réduire les calculs mapStateToProps inutiles et de restituer 👍
très bien
mais il construit toutes les pages quand j'espère construire une seule page
_traduction non officielle_
Redux est bon. Mais il y a trop de concepts, de réducteurs séparés, de sagas et d'actions (divisées en différents fichiers)
C'est un wrapper léger sur le framework existant (redux + react-router + redux-saga ...). Aucun nouveau concept impliqué. Code < 100 lignes. ( Inspiré par l'orme et le choo. )
C'est un framework, pas une bibliothèque. Comme Ember.js, il limite la façon dont vous écrivez chaque partie. C'est plus contrôlable pour le travail d'équipe. Dva encapsule toutes les dépendances à l'exception de react et react-dom en tant que peerDependencies
Son implémentation introduit le moins possible de nouvelles syntaxes. Il réutilise les dépendances. Pour exp., la définition du routeur est exactement de la même manière que le JSX de react-router.
La fonctionnalité de base est app.model
. Il encapsule le réducteur, l'état initial, l'action et la saga.
app.model({
namespace: 'products',
state: {
list: [],
loading: false,
},
subscriptions: [
function(dispatch) {
dispatch({type: 'products/query'});
},
],
effects: {
['products/query']: function*() {
yield call(delay(800));
yield put({
type: 'products/query/success',
payload: ['ant-tool', 'roof'],
});
},
},
reducers: {
['products/query'](state) {
return { ...state, loading: true, };
},
['products/query/success'](state, { payload }) {
return { ...state, loading: false, list: payload };
},
},
});
Nous avions l'habitude de créer sagas/products.js, reducers/products.js actions/products.js
et de passer de l'un à l'autre.
point clé:
key
du reducer
dans son objet rootReducer
initialState
de reducer
Voir des exemples
devtool
rechargement à chaudEffects
prend en charge plus de modèles saga
L'outil de développement prend en charge ?
Compatible avec redux-devtool, css livereload. Besoin de plus de travail pour le rechargement à chaud
Bon pour la prod env ?
Bien sur
Y compris toutes les fonctionnalités de redux + redux-saga ?
Oui
Compatibilité des navigateurs ?
Pas d'IE8 à cause de redux-saga. (Plus tard, peut appliquer thunk, promesse, observable en tant qu'extensions sur la couche d'effets)
s'il vous plaît similaire
['products/query']: function*() {}
['products/query'](state) {}
Quelle est la syntaxe ? Les tableaux peuvent-ils être utilisés comme noms de fonction ?
@clemTheDasher Le nom de la fonction peut être une clé calculée ( PAS de tableau) en JavaScript. Référence plus détaillée aux définitions de méthodes |
var obj = {
property( parameters… ) {},
*generator( parameters… ) {},
async property( parameters… ) {},
async* generator( parameters… ) {},
// with computed keys:
[property]( parameters… ) {},
*[generator]( parameters… ) {},
async [property]( parameters… ) {},
// compare getter/setter syntax:
get property() {},
set property(value) {}
};
Rapports de nouveaux arrivants, venez ici et continuez à travailler dur pour acquérir des connaissances frontales
@clemTheDasher C'est une propriété calculée.
Pourquoi le lien https://github.com/dvajs/dva/tree/master/examples/count est-il 404 ?
Apprendre!
regarde dieu
Dieu merci, merci pour l'open source
suis-je pas autorisé à apprendre de vous les gars!
J'ai appris, merci d'avoir un cadre aussi pratique à utiliser
Les liens de démonstration sur github ont expiré.
@sorrycc est-ce que dva prend en charge le rendu côté serveur maintenant ?
Le réducteur peut-il s'écrire ainsi :
const reducer = (state, { type, payload }) => { switch (type) { case 'products/query': return { ...state, loading: true, }; case 'products/query/success': return { ...state, loading: false, list: payload }; default return state; } } app.model({ reducer })
Cela permet d'appliquer certaines méthodes d'ordre supérieur au réducteur.
Le style d'écriture Redux est concis et une seule ligne est nécessaire pour modifier l'état, mais il semble que plusieurs lignes de code soient écrites ensemble via du sucre syntaxique. Mais je dois encore utiliser ...state
pour livrer le statut restant au prochain arrêt, sinon le statut sera incomplet. En d'autres termes, pendant la phase de réduction, un état peut être perdu s'il est écrit de manière incorrecte.
À certains égards, l'idée de Vuex est plus facile à lire et plus naturelle. Écrivez quelque chose comme ça (pas exactement).
const mutation = {
['products/query'](state) {
state.loading = true
},
['products/query/success'](state, payload) {
state.loading = false
state.list = payload
}
}
Du point de vue du code, je ne me soucie que de l'état que je modifie (de manière synchrone). Vuex devrait également envelopper une couche à l'extérieur pour la livraison de l'état suivant. Il est possible que des vérifications défensives (devinettes) soient également effectuées avant la livraison, ou que des hameçons soient plantés.
Demandez-moi si la page d'exemple du site officiel de dva ne peut pas sortir et signaler une erreur, s'agit-il d'une mise à niveau ?
s'il vous plaît similaire
['products/query']: function*() {} ['products/query'](state) {}
Quelle est la syntaxe ? Les tableaux peuvent-ils être utilisés comme noms de fonction ?
ES6 permet aux littéraux de définir des objets, (expression) comme nom de propriété de l'objet, c'est-à-dire de mettre l'expression entre crochets.
Comme
obj = {
['xxname']: 'what ever you defined',
['xxyy'](args) {
....
}
}
Il y a une question, "products/query" est utilisé pour traiter l'appel des réducteurs, et il est associé à l'espace de noms via une chaîne. Plus tard, si le projet devient plus grand, comme des centaines de méthodes. Si mon namspace doit être changé. Changer cent méthodes ?
@yesmeck 👍, le rôle de réducteur amplificateur a été sous-estimé auparavant.
Vous ne savez pas s'il y a du support ici ?
Commentaire le plus utile
Être rendu vivant par redux est tout simplement l'évangile. C'est trop simple et élégant. Grand éloge ! ! !
au fait, j'ai accidentellement vu un étranger le republier sur Twitter aujourd'hui, je pensais qu'il avait été écrit par un étranger, mais je ne m'attendais pas à ce que ce soit un camarade de classe d'Alipay, 👍