-
Vue:
npm create vue@latest
- Setup CLI avec plusieurs options de generation (typescript, eslint, framework de tests...).
- Projet hello world d'example.
- 139 packages (56Mo), 0 vulnerabilites.
- Build: 88K
-
React:
npx create-react-app <name>
- Generation directe sans options.
- Projet hello world d'example.
- 1508 packages (1511 avec react-router-dom, 432Mo), 6 vulnerabilites "high-severity".
- Build 948K
-
Les deux frameworks permettent le Lazy-loading par defaut, React est moins pratique a gerer dans certains cas mais il existe des bibliotheques qui ameliorent cet aspect.
-
Vue:
- Routeur initialise dans le projet d'example si l'option est selectionnee dans le quick start
- Initialisation via
app.use(<routeur>)
dansmain.js
, avec<routeur>
le resultat d'un appel acreateRouter()
dans lequel les routes sont detaillees - Navigation via composant
<RouterLink>
- Le composant correspondant a la route actuelle s'obtient via le composant
<RouterView />
-
React:
- Routeur necessitant le package
react-router-dom
non-inclus dans la base produite parcreate-react-app
- Initialisation via rendering du composant
<Routes>
dans la vue, contenant la definition de chaque<Route>
en enfant - Navigation via composant
<Link>
- Le composant correspondant a la route actuelle s'obtient via le composant
<Outlet />
- Routeur necessitant le package
-
Deux styles de scripting
-
Memes capacites: l'Options API est construite sur la Composition API
-
Options API plus structuree mais verbose, centree instance (beaucoup d'acces a
this
) -
Composition API plus flexible et proche du React, centree composition (duh), cad declaration de morceaux de state dans un scope et les combiner pour gerer la complexite
-
Composition API plus poussee, semble etre l'option privilegiee sur le long terme, mais beaucoup d'existant utilise l'Options API donc il faut savoir comprendre les deux
-
Reste de cette demo en Composition API (et en fonctionnel pour React)
-
Props en read-only, attributs du prop accessibles (donc mutable indirectement) dans les deux cas.
-
Vue:
- Possibilite de preciser le type d'un prop, s'il est required, et un validator simple
- Message console en cas de prop invalide, mais pas d'effet de bord, le prop continuera d'exister dans le code, handling manuel necessaire comme en react
- Separation script / template: afficher une liste se fait par un tag particulier sur une balise (
v-for
), meme principe pour le rendering conditionnel (v-if
etv-else
) - Passage statique:
prop=valeur
, passage dynamique::prop="javascript"
ouv-bind:prop="javascript"
- Possibilite de preciser le type d'un prop, s'il est required, et un validator simple
-
React:
- Sans typescript, peu de controle sur la validation ou le type souhaite
- JSX: melange de script et de balises, afficher une liste revient a iterer dessus en javascript et return la balise correspondante a chaque element, le rendering conditionnel est un test qui retourne une balise
- Passage statique:
prop=valeur
, passage dynamique:prop={javascript}
-
Vue:
- Un state reactif se declare avec
state = ref(defaultValue)
- Une valeur calculee se definit avec `result = computed(() => state.value === null ? "vide" : "non vide")
- Dans le
<script>
on accede au state avecstate.value
/state.value = newValue
, dans la template avecstate
/state = newValue
v-model="state"
s'occupe d'afficher le contenu du state dans l'input et de le mettre a jour si necessaire. S'adapte au type d'input:value/onInput
pour du texte,checked/onCheck
pour une checkbox, etc.- On peut reagir au changement du state avec
watch(state, (newValue, oldValue) => {...})
. Depuis Vue3 il est egalement possible de watch plusieurs sources a partir du meme handler:watch([a, b], ([newA, newB], [oldA, oldB]) => {...})
- Un state reactif se declare avec
-
React:
- Un state reactif se declare avec
[state, setState] = useState(defaultValue)
- Une valeur calculee se definit telle-quelle ou avec
useMemo(() => calculComplexe(state), [state])
- On accede au state via
state
(immutable) et on le met a jour viasetState(newValue)
- Il n'y a pas de binding bi-directionnel, il faut necessairement passer par le setter pour modifier le state. Il faut donc preciser pour chaque input
value={state} onChange={e => setState(e.target.value)}
ou equivalent selon le type d'input. - On peut reagir au changement du state avec
useEffect(() => {...}, [state])
. Il est possible d'observer plusieurs variables avec le memeuseEffect
mais on ne peut pas garder l'information de la valeur avant changement sans implementer un hook custom.
- Un state reactif se declare avec
- Base similaire: arbre des composants et inspection/edition de leurs props et state
- Vue propose plus d'informations sur les composants comme les fonctions internes, les listeners, le nom des variables en state, etc
- React propose un profiler permettant d'effectuer des captures pour obtenir un flame graph, Vue propose une timeline en temps reel de tous les evenements souris/clavier/composant et leur impact en performance
-
Vue:
- Comportement disponible par defaut en Vue.js: ajouter
scoped
a la balise<style>
du fichier .vue - Un style
scoped
d'un composant s'appliquera aussi a tous ses composants enfants - Utiliser des classes reste meilleur pour les performances de l'application que de laisser des elements HTML tels quels dans un style scoped.
- Comportement disponible par defaut en Vue.js: ajouter
-
React:
- Par defaut, tous les CSS sont merges tels quels lors du build. A partir du moment ou un CSS est importe dans un composant inclus dans le build, il sera applique a tout le code.
- Plusieurs manieres de gerer ce probleme: utilisation de CSS Modules (resultat proche du comportement de Vue, mais a ecrire explicitement, webpack doit etre config pour l'accepter), utilisation d'une bibliotheque "css-in-js" comme styled-components ou emotion (objectivement hideux et illisible, melange html + js + css dans le meme morceau de code), usage explicite de classes/ids et de div "containers" autour des composants (plus verbeux)
-
Equivalences React vs Vue
- props
- en parametre de la fonction-composant vs
defineProps()
- en parametre de la fonction-composant vs
- state
useState()
vsref()
- reactivite
useEffect()
vswatch()
- hooks de lifecycle
- Difficile avec la version fonctionnelle de React, acces direct aux hooks avec Vue
- dynamic rendering
{list.map((elt, idx) => <component props={elt} key={idx}>}
vs<component v-for="elt in list" :props="elt">
{condition && <component>}
vs<component v-if="condition">
{condition ? <component1> : <component2>}
vs<component1 v-if="condition"><component2 v-else>
- children components
{children}
vs<slots />
- props
-
Equivalences de bibliotheques courantes en React
- react-router -> vue-router
- Fonctionnement tres proche, navigation un peu differente (pour vue, plus proche de
window.history
que deuseNavigate()
- Fonctionnement tres proche, navigation un peu differente (pour vue, plus proche de
- Redux (lib externe) -> Pinia (anciennement Vuex)
- Fonctionnement tres proche, Pinia moins laborieux d'apres internet (pas test)
- react-query -> vue-query
- Les deux reposent sur TanStack Query, donc meme fonctionnement
- Scoped CSS (CSS Modules, Emotion, Styled Components...)
- Bibliotheque + configuration du bundler necessaire en React, Fonctionnement par defaut en Vue
- React Developer Tools -> Vue.js devtools
- react-router -> vue-router