Commit 5cb48d36 authored by Winnie Hellmann's avatar Winnie Hellmann Committed by Filipa Lacerda

Remove old service architecture from Vue docs

parent 0399b644
...@@ -2,27 +2,24 @@ ...@@ -2,27 +2,24 @@
To get started with Vue, read through [their documentation][vue-docs]. To get started with Vue, read through [their documentation][vue-docs].
## Vue architecture ## Examples
All new features built with Vue.js must follow a [Flux architecture][flux]. What is described in the following sections can be found in these examples:
The main goal we are trying to achieve is to have only one data flow and only one data entry.
In order to achieve this goal, you can either use [vuex](#vuex) or use the [store pattern][state-management], explained below:
Each Vue bundle needs a Store - where we keep all the data -, a Service - that we use to communicate with the server - and a main Vue component. - web ide: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/ide/stores
- security products: https://gitlab.com/gitlab-org/gitlab-ee/tree/master/ee/app/assets/javascripts/vue_shared/security_reports
- registry: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/registry/stores
Think of the Main Vue Component as the entry point of your application. This is the only smart ## Vue architecture
component that should exist in each Vue feature.
This component is responsible for:
1. Calling the Service to get data from the server
1. Calling the Store to store the data received
1. Mounting all the other components
![Vue Architecture](img/vue_arch.png) All new features built with Vue.js must follow a [Flux architecture][flux].
The main goal we are trying to achieve is to have only one data flow and only one data entry.
In order to achieve this goal we use [vuex](#vuex).
You can also read about this architecture in vue docs about [state management][state-management] You can also read about this architecture in vue docs about [state management][state-management]
and about [one way data flow][one-way-data-flow]. and about [one way data flow][one-way-data-flow].
### Components, Stores and Services ### Components and Store
In some features implemented with Vue.js, like the [issue board][issue-boards] In some features implemented with Vue.js, like the [issue board][issue-boards]
or [environments table][environments-table] or [environments table][environments-table]
...@@ -33,10 +30,8 @@ new_feature ...@@ -33,10 +30,8 @@ new_feature
├── components ├── components
│ └── component.vue │ └── component.vue
│ └── ... │ └── ...
├── stores ├── store
│ └── new_feature_store.js │ └── new_feature_store.js
├── services # only when not using vuex
│ └── new_feature_service.js
├── index.js ├── index.js
``` ```
_For consistency purposes, we recommend you to follow the same structure._ _For consistency purposes, we recommend you to follow the same structure._
...@@ -125,217 +120,6 @@ You can read more about components in Vue.js site, [Component System][component- ...@@ -125,217 +120,6 @@ You can read more about components in Vue.js site, [Component System][component-
#### Vuex #### Vuex
Check this [page](vuex.md) for more details. Check this [page](vuex.md) for more details.
#### Flux like state management
The Store is a class that allows us to manage the state in a single
source of truth. It is not aware of the service or the components.
The concept we are trying to follow is better explained by Vue documentation
itself, please read this guide: [State Management][state-management]
### A folder for the Service
**If you are using Vuex you won't need this step**
The Service is a class used only to communicate with the server.
It does not store or manipulate any data. It is not aware of the store or the components.
We use [axios][axios] to communicate with the server.
Refer to [axios](axios.md) for more details.
Axios instance should only be imported in the service file.
```javascript
import axios from '~/lib/utils/axios_utils';
```
### End Result
The following example shows an application:
```javascript
// store.js
export default class Store {
/**
* This is where we will iniatialize the state of our data.
* Usually in a small SPA you don't need any options when starting the store.
* In that case you do need guarantee it's an Object and it's documented.
*
* @param {Object} options
*/
constructor(options) {
this.options = options;
// Create a state object to handle all our data in the same place
this.todos = [];
}
setTodos(todos = []) {
this.todos = todos;
}
addTodo(todo) {
this.todos.push(todo);
}
removeTodo(todoID) {
const state = this.todos;
const newState = state.filter((element) => {element.id !== todoID});
this.todos = newState;
}
}
// service.js
import axios from '~/lib/utils/axios_utils'
export default class Service {
constructor(options) {
this.todos = axios.create({
baseURL: endpoint.todosEndpoint
});
}
getTodos() {
return this.todos.get();
}
addTodo(todo) {
return this.todos.put(todo);
}
}
// todo_component.vue
<script>
export default {
props: {
data: {
type: Object,
required: true,
},
},
};
</script>
<template>
<div>
<h1>
Title: {{data.title}}
</h1>
<p>
{{data.text}}
</p>
</div>
</template>
// todos_main_component.vue
<script>
import Store from 'store';
import Service from 'service';
import TodoComponent from 'todoComponent';
export default {
components: {
todo: TodoComponent,
},
/**
* Although most data belongs in the store, each component it's own state.
* We want to show a loading spinner while we are fetching the todos, this state belong
* in the component.
*
* We need to access the store methods through all methods of our component.
* We need to access the state of our store.
*/
data() {
const store = new Store();
return {
isLoading: false,
store: store,
todos: store.todos,
};
},
created() {
this.service = new Service('/todos');
this.getTodos();
},
methods: {
getTodos() {
this.isLoading = true;
this.service
.getTodos()
.then(response => {
this.store.setTodos(response);
this.isLoading = false;
})
.catch(() => {
this.isLoading = false;
// Show an error
});
},
addTodo(event) {
this.service
.addTodo({
title: 'New entry',
text: `You clicked on ${event.target.tagName}`,
})
.then(response => {
this.store.addTodo(response);
})
.catch(() => {
// Show an error
});
},
},
};
</script>
<template>
<div class="container">
<div v-if="isLoading">
<i
class="fa fa-spin fa-spinner"
aria-hidden="true" />
</div>
<div
v-if="!isLoading"
class="js-todo-list">
<template v-for='todo in todos'>
<todo :data="todo" />
</template>
<button
@click="addTodo"
class="js-add-todo">
Add Todo
</button>
</div>
<div>
</template>
// index.js
import todoComponent from 'todos_main_component.vue';
new Vue({
el: '.js-todo-app',
components: {
todoComponent,
},
render: createElement => createElement('todo-component' {
props: {
someProp: [],
}
}),
});
```
The [issue boards service][issue-boards-service]
is a good example of this pattern.
## Style guide ## Style guide
Please refer to the Vue section of our [style guide](style_guide_js.md#vue-js) Please refer to the Vue section of our [style guide](style_guide_js.md#vue-js)
...@@ -446,6 +230,5 @@ need to test the rendered output. [Vue][vue-test] guide's to unit test show us e ...@@ -446,6 +230,5 @@ need to test the rendered output. [Vue][vue-test] guide's to unit test show us e
[state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch [state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch
[one-way-data-flow]: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow [one-way-data-flow]: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow
[vue-test]: https://vuejs.org/v2/guide/unit-testing.html [vue-test]: https://vuejs.org/v2/guide/unit-testing.html
[issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6
[flux]: https://facebook.github.io/flux [flux]: https://facebook.github.io/flux
[axios]: https://github.com/axios/axios [axios]: https://github.com/axios/axios
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment