Mis à jour le mardi 7 mars 2017
  • 20 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

Ce cours est en vidéo.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Build a static app

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Javascript developers working with server-rendered HTML pages (as opposed to "single page application" frameworks like React) often observe an approach called progressive enhancement. In progressive enhancement, a web page was built in HTML first, with Javascript being added as an "enhancement" afterwards. This was often viewed as a way to maintain a functional web page when javascript was turned off, but it has other advantages, including semantics, accessibility, and separating concerns in the development process.

We'll take a cue from that pattern in developing our app, by creating a static version of our web page first, then adding the interactive functionality. To begin, we'll flesh out our component outline with some boilerplate component files.

So far all we know is which components we have, and which ones they will render. That's enough for now. Let's add the following files to the  ./src/  directory of our application.

 Products.js :

import React from 'react';
import Filters from './Filters.js';
import ProductForm from './ProductForm';
import ProductTable from './ProductTable.js';

class Products extends React.Component {
  render() {
    return (
      <div>
        <Filters ></Filters>
        <ProductTable ></ProductTable>
        <ProductForm ></ProductForm>
      </div>
    );
  } 
}

export default Products;

 Filters.js :

import React from 'react';

class Filters extends React.Component {
  render() {
    return (
    );
  }
}

export default Filters;

 ProductTable.js :

import React from 'react';
import ProductRow from './ProductRow.js';
import ProductTableHeader from './ProductTableHeader.js';

class ProductTable extends React.Component {
  render() {
    return (
      <div>
        <ProductTableHeader ></ProductTableHeader>
        <ProductRow ></ProductRow>
      </div>
    );
  }
}

export default ProductTable;

 ProductTableHeader.js :

import React from 'react';

class ProductTableHeader extends React.Component {
  render() {
    return(
    );
  }
}

export default ProductTableHeader;

 ProductRow.js :

import React from 'react';

class ProductRow extends React.Component {
  render() {
    return (
    );
  }
}

export default ProductRow;

 ProductForm.js :

import React from 'react';

class ProductForm extends React.Component {
  render() {
    return (
    );
  }
}

export default ProductForm;

 This of course doesn't render anything, but it shouldn't throw any errors either. The  ProductTable  component, in particular, will need to render multiple instances of the  ProductTableHeader  and  ProductTableRow  components. We'll address that next.

We'll need to include our JSON data somewhere at this point. Since the data will flow "down" to all the components that need it, we should represent this data in the highest level component it concerns. In this case, that would be the 'Products' component. To pass the data down to child components we'll use the  props  attribute. We end up with something like this:

 Products.js :

import React from 'react';
import Filters from './Filters.js';
import ProductForm from './ProductForm';
import ProductTable from './ProductTable.js';

var PRODUCTS = {
  '1': {id: 1, category: 'Musical Instruments', price: '$459.99', stocked: true, name: 'Clarinet'},
  '2': {id: 2, category: 'Musical Instruments', price: '$5,000', stocked: true, name: 'Cello'},
  '3': {id: 3, category: 'Musical Instruments', price: '$11,000', stocked: false, name: 'Fortepiano'},
  '4': {id: 4, category: 'Furniture', price: '$799', stocked: true, name: 'Chaise Lounge'},
  '5': {id: 5, category: 'Furniture', price: '$1,300', stocked: false, name: 'Dining Table'},
  '6': {id: 6, category: 'Furniture', price: '$100', stocked: true, name: 'Bean Bag'}
};

class Products extends React.Component {
  render() {
    return (
      <div>
        <Filters ></Filters>
        <ProductTable products={PRODUCTS} ></ProductTable>
        <ProductForm ></ProductForm>
      </div>
    );
  }
}

export default Products;

 Filters.js :

import React from 'react';

class Filters extends React.Component {
  render() {
    return (
      <form>
        <input type="text" placeholder="Search..." />
        <p>
          <input type="checkbox" />&nbsp;Only show stocked products
        </p>
      </form>
    );
  }
}

export default Filters;

To render a collection in React, we'll simply build up an array of  <ProductRow>  components by iterating over props.products. Since our data model is an object, not an array, we'll map it to an array for ease of use first, using the  Object.keys  and  Array.prototype.map  functions. You can check out their documentation for more information on this step.

Remember that JSX tags are compiled to normal JavaScript objects, and can be stored and passed around as such. This is pretty straightforward, but take note of the  key  attribute on the  <ProductRow>  component. Whenever you're building a list in React, you need to add unique keys to the items in the list, so that React can keep track of them when their order changes, and avoid unnecessary re-rendering.

We also need to pass the names of our columns to ProductTableHeader. We could do this by nesting them as content inside the  <ProductTableHeader>  and then referencing them via props.children. We aren't going to take that approach here because we want access to the name of the column in order to carry out our sorting actions. Instead we'll pass a 'column'  prop  to the  ProductTableHeader  component.:

 ProductTable.js :

import React from 'react';
import ProductRow from './ProductRow.js';
import ProductTableHeader from './ProductTableHeader.js';

class ProductTable extends React.Component {
  render() {
    let productsAsArray = Object.keys(this.props.products).map((pid) => this.props.products[pid]);
    let rows = [];

    productsAsArray.forEach((product) => {
      rows.push(
        <ProductRow product={product} key={product.id} ></ProductRow>
      );
    });

    return (
      <div>
        <table>
          <thead>
            <tr>
              <ProductTableHeader column="name" ></ProductTableHeader>
              <ProductTableHeader column="price" ></ProductTableHeader>
            </tr>
          </thead>
          <tbody>{rows}</tbody>
        </table>
      </div>
    );
  }
}

export default ProductTable;

For the header component, we want to highlight the button that reflects the current sort order. We'll use a CSS class for the styles, that we'll define in a component css library and include in our jsx:

 ProductTableHeader.js :

import React from 'react';
import './ProductTableHeader.css';

class ProductTableHeader extends React.Component {
  render() {
    return(
      <th>
        {this.props.column}
        <button className="ProductTableHeader-current">&#x25B2;</button>
        <button>&#x25BC;</button>
      </th>
    );
  }
}

export default ProductTableHeader;

Remember, this css file goes right in the  ./src  directory alongside your jsx files:

 ProductTableHeader.css :

.ProductTableHeader-current {
  background-color: #0ff;
}

We'll use CSS to indicate out-of-stock items in the same way:

 ProductRow.js :

import React from 'react';
import './ProductRow.css';

class ProductRow extends React.Component {
  render() {
    return (
      <tr>
        <td>
          <span className={this.props.product.stocked ? '' : 'ProductRow-out-of-stock'}>
            {this.props.product.name}
          </span>
        </td>
        <td>
           {this.props.product.price}
        </td>
        <td>
           <button onClick={this.destroy} style={{color: 'red'}}>x</button>
        </td>
      </tr>
    );
  }
}

export default ProductRow;

 ProductRow.css :

.ProductRow-out-of-stock {
  color: red;
}

 ProductForm.js :

import React from 'react';

class ProductForm extends React.Component {
  render() {
    return (
      <form>
        <h3>Enter a new product</h3>
        <p>
          <label>
            Name
            <br />
            <input type="text" name="name" />
          </label>
        </p>
        <p>
          <label>
            Category
            <br />
            <input type="text" name="category" />
          </label>
        </p>
        <p>
          <label>
            Price
            <br />
            <input type="text" name="price" />
          </label>
        </p>
        <p>
          <label>
            <input type="checkbox" name="stocked" />
            &nbsp;In stock?
          </label>
        </p>
        <input type="submit" value="Save" />
      </form>
    );
  }
}

export default ProductForm;

Finally, let's render our Products component from the  App  component:

 App.js :

import React from 'react';
import Products from './Products.js';

class App extends React.Component {
  render() {
    return (
      <div>
        <header className="App-header"><h1>My React App</h1></header>
        <section>
          <Products ></Products>
        </section>
      </div>
    );
  }
} 

export default App;

At this point, you should be able to make changes to the data model (the  PROJECTS  const) and see them reflected in the UI. Try changing the number of projects, or their attributes, and see how it's reflected in the UI.

Exemple de certificat de réussite
Exemple de certificat de réussite