Skip to content

Traduction data.md #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 27, 2017
2 changes: 1 addition & 1 deletion en/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
- [Écrire du code universel (En)](universal.md)
- [Structure de code (En)](structure.md)
- [Routage et scission du code](routing.md)
- [Pré-chargement et état (En)](data.md)
- [Récupération de données et état (En)](data.md)
- [Hydratation côté client (En)](hydration.md)
- [Introduction à l'empaquetage (En)](bundle-renderer.md)
- [Configuration de pré-compilation (En)](build-config.md)
Expand Down
122 changes: 61 additions & 61 deletions en/data.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Pré-chargement et état (En) <br><br> *Cette page est en cours de traduction française. Revenez une autre fois pour lire une traduction achevée ou [participez à la traduction française ici](https://github.com/vuejs-fr/vue-ssr-docs).*
# Récupération de données et état

## Data Store
## Gestionnaire d'état des données

During SSR, we are essentially rendering a "snapshot" of our app, so if the app relies on some asynchronous data, **these data need to be pre-fetched and resolved before we start the rendering process**.
Pendant le SSR, nous allons essentiellement faire le rendu d'un « instantané » de notre application, aussi si votre application est liée à des données asynchrones, **ces données vont devoir être pré-chargées et résolues avant de débuter la phase de rendu**.

Another concern is that on the client, the same data needs to be available before we mount the client side app - otherwise the client app would render using different state and the hydration would fail.
Un autre point important côté client ; les mêmes données doivent être disponibles avant que l'application ne soit montée, autrement, l'application côté client va faire le rendu d'un état différent et l'hydratation va échouer.

To address this, the fetched data needs to live outside the view components, in a dedicated data store, or a "state container". On the server, we can pre-fetch and fill data into the store before rendering. In addition, we will serialize and inline the state in the HTML. The client-side store can directly pick up the inlined state before we mount the app.
Pour résoudre cela, les données pré-chargées doivent vivre en dehors de la vue du composant, dans un gestionnaire de données, ou dans un « gestionnaire d'état ». Côté serveur, nous pouvons pré-charger et remplir les données dans le gestionnaire de données avant le rendu. De plus, nous allons sérialiser et injecter l'état dans le HTML. Le gestionnaire de données côté client pourra directement récupérer l'état depuis le HTML avant que l'application ne soit montée.

We will be using the official state management library [Vuex](https://github.com/vuejs/vuex/) for this purpose. Let's create a `store.js` file, with some mocked logic for fetching an item based on an id:
Nous allons utiliser le gestionnaire d'état officiel (« store ») de la bibliothèque [Vuex](https://github.com/vuejs/vuex/) pour cette partie. Créons un fichier `store.js`, avec divers jeux de logique pour pré-charger un élément en nous basant sur un identifiant :

``` js
// store.js
Expand All @@ -17,8 +17,8 @@ import Vuex from 'vuex'

Vue.use(Vuex)

// Assume we have a universal API that returns Promises
// and ignore the implementation details
// Supposons que nous ayons une API universelle retournant
// des Promesses (« Promise ») et ignorons les détails de l'implémentation
import { fetchItem } from './api'

export function createStore () {
Expand All @@ -28,8 +28,8 @@ export function createStore () {
},
actions: {
fetchItem ({ commit }, id) {
// return the Promise via `store.dispatch()` so that we know
// when the data has been fetched
// retournant la Promesse via `store.dispatch()`, nous savons
// quand les données ont été pré-chargées
return fetchItem(id).then(item => {
commit('setItem', { id, item })
})
Expand All @@ -44,7 +44,7 @@ export function createStore () {
}
```

And update `app.js`:
Et mettons à jour `app.js`:

``` js
// app.js
Expand All @@ -55,32 +55,32 @@ import { createStore } from './store'
import { sync } from 'vuex-router-sync'

export function createApp () {
// create router and store instances
// créer le routeur et l'instance du store
const router = createRouter()
const store = createStore()

// sync so that route state is available as part of the store
// synchroniser pour que l'état de la route soit disponible en tant que donnée du store
sync(store, router)

// create the app instance, injecting both the router and the store
// créer l'instance de l'application, injecter le routeur et le store
const app = new Vue({
router,
store,
render: h => h(App)
})

// expose the app, the router and the store.
// exposer l'application, le routeur et le store.
return { app, router, store }
}
```

## Logic Collocation with Components
## Collocation logique avec les composants

So, where do we place the code that dispatches the data-fetching actions?
Donc, où devons nous appeler le code en charge de l'action de récupération de données ?

The data we need to fetch is determined by the route visited - which also determines what components are rendered. In fact, the data needed for a given route is also the data needed by the components rendered at that route. So it would be natural to place the data fetching logic inside route components.
Les données que nous avons besoin de pré-charger sont déterminées par la route visitée, qui va aussi déterminer quels composants vont être rendus. En fait, les données nécessaires a une route donnée sont aussi les données nécessaires aux composants pour être rendus pour une route. Aussi il serait naturel de placer la logique de récupération de données à l'intérieur des composants de route.

We will expose a custom static function `asyncData` on our route components. Note because this function will be called before the components are instantiated, it doesn't have access to `this`. The store and route information needs to be passed in as arguments:
Nous allons exposer une fonction statique personnalisée `asyncData` sur nos composants de route. Notez que, puisque cette fonction va être appelée avant l'instanciation des composants, l'accès à `this` ne sera pas possible. Le store et les informations de route ont donc besoin d'être passés en tant qu'arguments :

``` html
<!-- Item.vue -->
Expand All @@ -91,12 +91,12 @@ We will expose a custom static function `asyncData` on our route components. Not
<script>
export default {
asyncData ({ store, route }) {
// return the Promise from the action
// retourner la Promesse depuis l'action
return store.dispatch('fetchItem', route.params.id)
},

computed: {
// display the item from store state.
// afficher l'élément depuis l'état du store.
item () {
return this.$store.state.items[this.$route.params.id]
}
Expand All @@ -105,9 +105,9 @@ export default {
</script>
```

## Server Data Fetching
## Récupération de données côté serveur

In `entry-server.js` we can get the components matched by a route with `router.getMatchedComponents()`, and call `asyncData` if the component exposes it. Then we need to attach resolved state to the render context.
Dans `entry-server.js` nous pouvons obtenir les composants qui concordent avec une route grâce à `router.getMatchedComponents()`, et appeler `asyncData` si le composant l'expose. Nous avons ensuite besoin d'attacher l'état résolu au contexte de rendu.

``` js
// entry-server.js
Expand All @@ -125,7 +125,7 @@ export default context => {
return reject({ code: 404 })
}

// call `asyncData()` on all matched route components
// appeler `asyncData()` sur toutes les routes concordantes
Promise.all(matchedComponents.map(Component => {
if (Component.asyncData) {
return Component.asyncData({
Expand All @@ -134,11 +134,11 @@ export default context => {
})
}
})).then(() => {
// After all preFetch hooks are resolved, our store is now
// filled with the state needed to render the app.
// When we attach the state to the context, and the `template` option
// is used for the renderer, the state will automatically be
// serialized and injected into the HTML as window.__INITIAL_STATE__.
// Après que chaque hook de pré-chargement soit résolu, notre store est maintenant
// rempli avec l'état nécessaire au rendu de l'application.
// Quand nous attachons l'état au contexte, et que l'option `template`
// est utilisée pour faire le rendu, l'état va automatiquement être
// être sérialisé et injecté dans le HTML en tant que `window.__INITIAL_STATE__`.
context.state = store.state

resolve(app)
Expand All @@ -148,7 +148,7 @@ export default context => {
}
```

When using `template`, `context.state` will automatically be embedded in the final HTML as `window.__INITIAL_STATE__` state. On the client, the store should pick up the state before mounting the application:
En utilisant `template`, `context.state` va automatiquement être encapsulé dans le HTML final en tant qu'état `window.__INITIAL_STATE__`. Côté client, le store voudra récupérer cet état avant de monter l'application :

``` js
// entry-client.js
Expand All @@ -160,32 +160,32 @@ if (window.__INITIAL_STATE__) {
}
```

## Client Data Fetching
## Récupération de données côté client

On the client, there are two different approaches for handling data fetching:
Côté client, il y a deux différentes approches pour gérer du récapération de données :

1. **Resolve data before route navigation:**
1. **Résoudre les données avant de changer de route :**

With this strategy, the app will stay on the current view until the data needed by the incoming view has been resolved. The benefit is that the incoming view can directly render the full content when it's ready, but if the data fetching takes a long time, the user will feel "stuck" on the current view. It is therefore recommended to provide a data loading indicator if using this strategy.
Avec cette stratégie, l'application va rester sur la vue courante jusqu'à ce que les données nécessaires à la vue suivante soient résolues. L'avantage est que la vue suivante pourra faire le rendu complet du contenu aussitôt qu'il sera prêt, mais si les données mettent trop de temps à charger, l'utilisateur va se sentir « bloquer » sur la vue courante. C'est pourquoi il est recommandé de fournir un indicateur de chargement si vous utilisez cette stratégie.

We can implement this strategy on the client by checking matched components and invoking their `asyncData` function inside a global route hook. Note we should register this hook after the initial route is ready so that we don't unnecessarily fetch the server-fetched data again.
Nous pouvons implémenter cette stratégie côté client en vérifiant la concordance des composants et en exécutant leurs fonctions `asyncData` à l'intérieur du hook global du routeur. Notez que nous devrions enregistrer ce hook après que la route initiale ne soit prête et donc il n'est pas nécessaire de pré-charger de nouveau les données du serveur ayant déjà été pré-chargées.

``` js
// entry-client.js

// ...omitting unrelated code
// ...omission du code sans rapport

router.onReady(() => {
// Add router hook for handling asyncData.
// Doing it after initial route is resolved so that we don't double-fetch
// the data that we already have. Using `router.beforeResolve()` so that all
// async components are resolved.
// Ajouter le hook du routeur pour gérer `asyncData`
// Cela étant fait après la résolution de la route initial, évitons une double récupération de données
// des données que nous avons déjà. Utilisation de `router.beforeResolve()`, ainsi tous
// les composants asynchrones sont résolues.
router.beforeResolve((to, from, next) => {
const matched = router.getMatchedComponents(to)
const prevMatched = router.getMatchedComponents(from)

// we only care about none-previously-rendered components,
// so we compare them until the two matched lists differ
// nous allons uniquement nous occuper des composants qui n'ont pas déjà été rendu
// aussi nous allons les comparer jusqu'à ce que deux éléments concordant diffères
let diffed = false
const activated = matched.filter((c, i) => {
return diffed || (diffed = (prevMatched[i] !== c))
Expand All @@ -195,15 +195,15 @@ On the client, there are two different approaches for handling data fetching:
return next()
}

// this is where we should trigger a loading indicator if there is one
// c'est ici qu'il faudrait lancer un indicateur de chargement si nous en avions un

Promise.all(activated.map(c => {
if (c.asyncData) {
return c.asyncData({ store, route: to })
}
})).then(() => {

// stop loading indicator
// arrêt de l'indicateur de chargement

next()
}).catch(next)
Expand All @@ -213,20 +213,20 @@ On the client, there are two different approaches for handling data fetching:
})
```

2. **Fetch data after the matched view is rendered:**
2. **Récupérer les données après que les vues concordantes soient rendues :**

This strategy places the client-side data-fetching logic in a view component's `beforeMount` function. This allows the views to switch instantly when a route navigation is triggered, so the app feels a bit more responsive. However, the incoming view will not have the full data available when it's rendered. It is therefore necessary to have a conditional loading state for each view component that uses this strategy.
Cette stratégie place la logique de récupération de données côté client dans la fonction `beforeMount` de la vue du composant. Cela permet aux vues de changer instantanément quand un changement de route est enclenché, aussi l'application semblera un peu plus réactive. Cependant, la vue suivante n'aura pas l'intégralité de ses données disponibles lors du rendu. Il est donc nécessaire d'avoir un état de chargement conditionnel pour chaque vue de composant utilisant cette stratégie.

This can be achieved with a client-only global mixin:
Cela peut être réalisé avec un mixin global uniquement côté client :

``` js
Vue.mixin({
beforeMount () {
const { asyncData } = this.$options
if (asyncData) {
// assign the fetch operation to a promise
// so that in components we can do `this.dataPromise.then(...)` to
// perform other tasks after data is ready
// assigner une opération de récupération de données à une Promesse
// ainsi tout ce que nous devons faire dans un composant est `this.dataPromise.then(...)`
// pour exécuter la suite des tâches une fois que les données sont prêtes
this.dataPromise = asyncData({
store: this.$store,
route: this.$route
Expand All @@ -236,7 +236,7 @@ On the client, there are two different approaches for handling data fetching:
})
```

The two strategies are ultimately different UX decisions and should be picked based on the actual scenario of the app you are building. But regardless of which strategy you pick, the `asyncData` function should also be called when a route component is reused (same route, but params or query changed. e.g. from `user/1` to `user/2`). We can also handle this with a client-only global mixin:
Les deux stratégies conduisent à une expérience utilisateur singulièrement différente et doivent être choisis en fonction du scénario de l'application que vous construisez. Mais indépendamment de votre choix de stratégie, la fonction `asyncData` devrait également être appelée quand la route d'un composant est de nouveau utilisée (même route, mais avec des paramètres ou une demande « query » différente comme par ex. avec `utilisateur/1` et `utilisateur/2`). Nous pouvons également réaliser ceci avec un mixin global uniquement côté client.

``` js
Vue.mixin({
Expand All @@ -254,16 +254,16 @@ Vue.mixin({
})
```

## Store Code Splitting
## Scission de code du Store

In a large application, our vuex store will likely be split into multiple modules. Of course, it is also possible to code-split these modules into corresponding route component chunks. Suppose we have the following store module:
Dans une grosse application, notre store Vuex va très probablement être scinder dans de multiples modules. Bien sur, il est aussi possible de scinder le code de ces modules en fragments correspondant aux routes. Supposons que nous ayons le module store suivant :

``` js
// store/modules/foo.js
export default {
namespaced: true,
// IMPORTANT: state must be a function so the module can be
// instantiated multiple times
// IMPORTANT: l'état doit être une fonction sinon le module ne
// pourra pas être instancié de multiples fois
state: () => ({
count: 0
}),
Expand All @@ -276,7 +276,7 @@ export default {
}
```

We can use `store.registerModule` to lazy-register this module in a route component's `asyncData` hook:
Nous pouvons utiliser `store.registerModule` pour enregistrer ce module à la volée dans le hook `asyncData` du composant :

``` html
// inside a route component
Expand All @@ -285,7 +285,7 @@ We can use `store.registerModule` to lazy-register this module in a route compon
</template>

<script>
// import the module here instead of in `store/index.js`
// importer le module d'ici et non de `store/index.js`
import fooStoreModule from '../store/modules/foo'

export default {
Expand All @@ -294,8 +294,8 @@ export default {
return store.dispatch('foo/inc')
},

// IMPORTANT: avoid duplicate module registration on the client
// when the route is visited multiple times.
// IMPORTANT: il faut éviter le double enregistrement de module côté client
// quand la route est visitée plusieurs fois.
destroyed () {
this.$store.unregisterModule('foo')
},
Expand All @@ -309,8 +309,8 @@ export default {
</script>
```

Because the module is now a dependency of the route component, it will be moved into the route component's async chunk by webpack.
Parce que le module est maintenant une dépendance du composant de route, il peut a présent être déplacer dans un fragment de composant de route par webpack.

---

Phew, that was a lot of code! This is because universal data-fetching is probably the most complex problem in a server-rendered app and we are laying the groundwork for easier further development. Once the boilerplate is set up, authoring individual components will be actually quite pleasant.
Fiou, cela fait pas mal de code ! Cela est dû au fait que le pré-chargement universel est probablement le problème le plus complexe d'une application avec rendu côté serveur et nous avons poser les bases pour un développement futur plus simple. Maintenant que cette base est mise en place, modifier des composants individuellement sera en fait plutôt agréable.