Logomotion: mise à jour introduction framework javascript
This commit is contained in:
parent
7add972706
commit
3d2afb8b17
|
@ -379,12 +379,12 @@ Implémenter une application minimaliste de gestion de tâches avec Riot. Cette
|
||||||
|Avantages|Inconvénients|
|
|Avantages|Inconvénients|
|
||||||
|:-|:-|
|
|:-|:-|
|
||||||
|Grande communauté, très active | Changement de license puis rétropédalage en 2017 |
|
|Grande communauté, très active | Changement de license puis rétropédalage en 2017 |
|
||||||
| Maintenu et utilisé par Facebook en interne | Nécessité de mettre en place un pipeline de transpilage |
|
| Maintenu et utilisé par Facebook | Nécessité de mettre en place un pipeline de transpilage |
|
||||||
| Architecture Flux | Architecture Flux |
|
| Architecture Flux | Architecture Flux |
|
||||||
| Possibilité de faire des applications "isomorphiques" avec NodeJS |
|
| Possibilité de faire des applications "isomorphiques" avec NodeJS |
|
||||||
| "React Native" |
|
| Projet "React Native" |
|
||||||
| API stable |
|
| API stable |
|
||||||
| Virtual DOM |
|
| Virtual DOM ([voir cet article](https://auth0.com/blog/face-off-virtual-dom-vs-incremental-dom-vs-glimmer/)) |
|
||||||
| Moteurs "lightweight" compatibles |
|
| Moteurs "lightweight" compatibles |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -601,6 +601,8 @@ export default Clock
|
||||||
|
|
||||||
![center](./img/flux-simple-f8-diagram-with-client-action-1300w.png)
|
![center](./img/flux-simple-f8-diagram-with-client-action-1300w.png)
|
||||||
|
|
||||||
|
[Voir une description des concepts](https://github.com/facebook/flux/tree/master/examples/flux-concepts)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Exercice
|
## Exercice
|
||||||
|
@ -641,6 +643,8 @@ Implémenter une application minimaliste de gestion de tâches avec React (sans
|
||||||
|Long-term support (1 an)|
|
|Long-term support (1 an)|
|
||||||
|Documentation exhaustive|
|
|Documentation exhaustive|
|
||||||
|Ember Data|
|
|Ember Data|
|
||||||
|
|Ember Inspector|
|
||||||
|
|Ember CLI|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -651,7 +655,6 @@ Implémenter une application minimaliste de gestion de tâches avec React (sans
|
||||||
### Templates
|
### Templates
|
||||||
### Modèles
|
### Modèles
|
||||||
### Contrôleurs
|
### Contrôleurs
|
||||||
### Composants
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -668,18 +671,53 @@ ember serve
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Routes
|
## Routes (1)
|
||||||
|
|
||||||
### Générer une nouvelle route
|
### Générer une nouvelle route
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
ember generate route foo
|
ember generate route posts
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Templates
|
## Routes (2)
|
||||||
|
|
||||||
|
### Attacher un/plusieurs modèles à une route
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// app/routes/posts.js
|
||||||
|
import Route from '@ember/routing/route';
|
||||||
|
|
||||||
|
export default Route.extend({
|
||||||
|
model() {
|
||||||
|
return this.get('store').findAll('post');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Routes (3)
|
||||||
|
|
||||||
|
### Effectuer une redirection
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// app/routes/index.js
|
||||||
|
import Route from '@ember/routing/route';
|
||||||
|
|
||||||
|
export default Route.extend({
|
||||||
|
beforeModel() {
|
||||||
|
this.transitionTo('posts');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Templates (1)
|
||||||
|
|
||||||
|
### Syntaxe générale
|
||||||
```handlebars
|
```handlebars
|
||||||
{{!-- Interpolation de variable --}}
|
{{!-- Interpolation de variable --}}
|
||||||
{{ myVar }}
|
{{ myVar }}
|
||||||
|
@ -691,16 +729,183 @@ ember generate route foo
|
||||||
{{#block params... }}
|
{{#block params... }}
|
||||||
...
|
...
|
||||||
{{/block}}
|
{{/block}}
|
||||||
|
|
||||||
|
{{!-- Helpers imbriqués --}}
|
||||||
|
{{sum (multiply 2 4) 2}}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Modèles
|
## Templates (2)
|
||||||
|
|
||||||
|
### "Blocks" de base
|
||||||
|
```handlebars
|
||||||
|
{{!-- Condition --}}
|
||||||
|
{{if myVar}}
|
||||||
|
Maybe...
|
||||||
|
{{else}}
|
||||||
|
Or not.
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{!-- Boucle --}}
|
||||||
|
{{#each people as |person|}}
|
||||||
|
<li>Hello, {{person.name}}!</li>
|
||||||
|
{{/each}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Templates (3)
|
||||||
|
|
||||||
|
### "Helpers" spécifiques
|
||||||
|
```handlebars
|
||||||
|
{{!-- Affiche myVar[key] (accès dynamique aux variables exposées dans le controleur) --}}
|
||||||
|
{{get myVar "key"}}
|
||||||
|
|
||||||
|
{{!-- Affiche le contenu de la (sous) route --}}
|
||||||
|
{{outlet}}
|
||||||
|
|
||||||
|
{{!-- Modèle exposé par la route --}}
|
||||||
|
{{model}}
|
||||||
|
|
||||||
|
{{!-- Affiche un lien vers la route donnée --}}
|
||||||
|
{{link-to routeName}}
|
||||||
|
|
||||||
|
{{!-- Attacher une action à un élément (onclick) --}}
|
||||||
|
<button {{action "myAction"}}>Do it !</button>
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contrôleurs (1)
|
||||||
|
|
||||||
|
### Générer un contrôleur
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ember generate controller posts
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contrôleurs (2)
|
||||||
|
|
||||||
|
### Exposer des variables pour le template
|
||||||
|
|
||||||
|
```shell
|
||||||
|
import Controller from '@ember/controller';
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
foo: "bar" // {{ foo }} dans le template associé
|
||||||
|
});
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contrôleurs (3)
|
||||||
|
|
||||||
|
### Actions
|
||||||
|
|
||||||
|
```shell
|
||||||
|
import Controller from '@ember/controller';
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
|
||||||
|
foo: "bar"
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
myAction: function() {
|
||||||
|
// On modifie la valeur de "foo"
|
||||||
|
// Si "foo" est utilisé dans le template, il sera automatiquement mis à jour
|
||||||
|
this.set("foo", "hello world");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Modèles (1)
|
||||||
|
|
||||||
### Générer un nouveau modèle
|
### Générer un nouveau modèle
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
ember generate model bar
|
ember generate model post
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Modèles (2)
|
||||||
|
|
||||||
|
### Définition d'un modèle
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// app/models/comment.js
|
||||||
|
import DS from 'ember-data';
|
||||||
|
|
||||||
|
export default DS.Model.extend({
|
||||||
|
|
||||||
|
// Simple attributs
|
||||||
|
text: DS.attr('string'),
|
||||||
|
|
||||||
|
// Relations
|
||||||
|
post: DS.belongsTo('post')
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// app/models/post.js
|
||||||
|
import DS from 'ember-data';
|
||||||
|
|
||||||
|
export default DS.Model.extend({
|
||||||
|
|
||||||
|
// Simples attributs
|
||||||
|
title: DS.attr('string'),
|
||||||
|
content: DS.attr('string'),
|
||||||
|
|
||||||
|
// Relations
|
||||||
|
comments: DS.hasMany('comment')
|
||||||
|
|
||||||
|
});
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Modèles (3)
|
||||||
|
|
||||||
|
### Manipuler une instance de modèle
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// app/controllers/posts.js
|
||||||
|
|
||||||
|
// Créer une nouvelle instance
|
||||||
|
var post = store.createRecord('post', {
|
||||||
|
title: 'Mon article',
|
||||||
|
content: 'Lorem ipsum'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Modifier l'instance
|
||||||
|
post.set('title', 'Foo bar');
|
||||||
|
|
||||||
|
// Sauvegarde de l'instance
|
||||||
|
post.save().then(() => console.log("Post saved !"));
|
||||||
|
|
||||||
|
// Supprimer l'instance
|
||||||
|
post.destroyRecord().then(() => console.log("Post deleted !"));
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Modèles (4)
|
||||||
|
|
||||||
|
### Effectuer des requêtes sur le "store"
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// app/controllers/posts.js
|
||||||
|
|
||||||
|
// Récupérer toutes les instances de "post"
|
||||||
|
var posts = this.get('store').findAll('post');
|
||||||
|
|
||||||
|
// Requête avec filtre
|
||||||
|
var posts = this.get('store').query('post', {
|
||||||
|
filter: {
|
||||||
|
title: "Foo Bar"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 51eafba3eadbbce1833b76d11667461e14cb5197
|
|
@ -0,0 +1 @@
|
||||||
|
{ "presets": ["react", "es2015"] }
|
|
@ -0,0 +1 @@
|
||||||
|
/node_modules
|
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import HelloWorld from './components/hello-world'
|
||||||
|
import PropsExample from './components/props-example'
|
||||||
|
import Clock from './components/clock-lifecycle'
|
||||||
|
import Counter from './components/counter'
|
||||||
|
|
||||||
|
ReactDOM.render(<HelloWorld />, document.getElementById('app'))
|
||||||
|
ReactDOM.render(<Clock />, document.getElementById('clock'))
|
||||||
|
ReactDOM.render(<Counter />, document.getElementById('counter'))
|
34
developpement/intro_javascript/ressources/react-demo/components/clock-lifecycle.js
vendored
Normal file
34
developpement/intro_javascript/ressources/react-demo/components/clock-lifecycle.js
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
class Clock extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
time: new Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
console.log('mount')
|
||||||
|
this.intervalId = setInterval(this.tick.bind(this), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
console.log('unmount')
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>Time: { this.state.time.toString() }</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() {
|
||||||
|
this.setState({ time: new Date() });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Clock
|
|
@ -0,0 +1,26 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
class Clock extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
time: new Date()
|
||||||
|
}
|
||||||
|
setInterval(this.tick.bind(this), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>Time: { this.state.time.toString() }</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() {
|
||||||
|
this.setState({ time: new Date() });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default Clock
|
|
@ -0,0 +1,41 @@
|
||||||
|
// components/counter.js
|
||||||
|
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
class Counter extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
// On fait appel au constructeur de la classe
|
||||||
|
// parente
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
// Initialisation du "state" du composant
|
||||||
|
this.state = {
|
||||||
|
count: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode de rendu du composant
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Count: <span>{ this.state.count }</span>
|
||||||
|
<button onClick={ () => this.increment() }>+1</button>
|
||||||
|
<button onClick={ () => this.decrement() }>-1</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// La méthode increment() incrémente la valeur du compteur de 1
|
||||||
|
increment() {
|
||||||
|
this.setState(prevState => ({ count: prevState.count+1 }))
|
||||||
|
}
|
||||||
|
|
||||||
|
// La méthode decrement() incrémente la valeur du compteur de 1
|
||||||
|
decrement() {
|
||||||
|
this.setState(prevState => ({ count: prevState.count-1 }))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Counter
|
17
developpement/intro_javascript/ressources/react-demo/components/hello-world.js
vendored
Normal file
17
developpement/intro_javascript/ressources/react-demo/components/hello-world.js
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
class HelloWorld extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className='hello-world'>
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
<p>Welcome to React</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default HelloWorld
|
13
developpement/intro_javascript/ressources/react-demo/components/props-example.js
vendored
Normal file
13
developpement/intro_javascript/ressources/react-demo/components/props-example.js
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
class PropsExample extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<span>{ this.props.text }</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PropsExample
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "react-demo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^16.2.0",
|
||||||
|
"react-dom": "^16.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-cli": "^6.26.0",
|
||||||
|
"babel-loader": "^7.1.2",
|
||||||
|
"babel-preset-es2015": "^6.24.1",
|
||||||
|
"babel-preset-react": "^6.24.1",
|
||||||
|
"css-loader": "^0.28.8",
|
||||||
|
"path": "^0.12.7",
|
||||||
|
"style-loader": "^0.19.1",
|
||||||
|
"webpack": "^3.10.0",
|
||||||
|
"webpack-dev-server": "^2.10.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "webpack-dev-server",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>"Simple" React with Webpack</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id='app'></div>
|
||||||
|
---
|
||||||
|
<div id='props-example'></div>
|
||||||
|
---
|
||||||
|
<div id='clock'></div>
|
||||||
|
---
|
||||||
|
<div id='counter'></div>
|
||||||
|
<script src='/bundle.js'></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,20 @@
|
||||||
|
var webpack = require('webpack')
|
||||||
|
var path = require('path')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: path.resolve(__dirname, 'app'),
|
||||||
|
output: {
|
||||||
|
path: __dirname + '/dist',
|
||||||
|
publicPath: '/',
|
||||||
|
filename: 'bundle.js'
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
contentBase: path.resolve(__dirname, 'public')
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
loaders: [
|
||||||
|
{test: /\.js$/, exclude: /node_modules/, loaders: ['babel-loader']},
|
||||||
|
{test: /(\.css)$/, loaders: ['style-loader', 'css-loader']}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,6 @@ class AppKernel extends Kernel
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
|
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
|
||||||
new Symfony\Bundle\TwigBundle\TwigBundle(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,15 +31,15 @@ class AppKernel extends Kernel
|
||||||
// PHP equivalent of config.yml
|
// PHP equivalent of config.yml
|
||||||
$c->loadFromExtension('framework', array(
|
$c->loadFromExtension('framework', array(
|
||||||
'secret' => 'S0ME_SECRET',
|
'secret' => 'S0ME_SECRET',
|
||||||
'templating' => [
|
// 'templating' => [
|
||||||
'engine' => [
|
// 'engine' => [
|
||||||
'twig'
|
// 'twig'
|
||||||
],
|
// ],
|
||||||
],
|
// ],
|
||||||
));
|
));
|
||||||
$c->loadFromExtension('twig', [
|
// $c->loadFromExtension('twig', [
|
||||||
'default_path' => __DIR__.'/../templates',
|
// 'default_path' => __DIR__.'/../templates',
|
||||||
]);
|
// ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configuration des routes
|
// Configuration des routes
|
||||||
|
|
Loading…
Reference in New Issue