Widoki i szablony

JSX jest mechanizmem wystarczającym do tworzenia dynamicznych szablonów. Istnieją moduły rozszerzające tą funkcjonalność (na przykład: http://wix.github.io/react-templates/) o możliwość kodowania pętli, warunków etc…. Użyteczność tego jest jednak kontrowersyjna, a na dodatek wystepują problemy z integracją tego modułu z React. Możliwości JSX takie jak użycie list, czy renderowanie warunkowe w zupełności wystarczają do stworzenia złożonych widoków.

Renderowanie warunkowe

Render może być warunkowy:

render () { 
const isOK = true 
return ( <div> 
        <h1> React {isOK ? <strong> is good</strong> : <span> is not good</span> } 
        </h1> 
        </div> ) }

null – nie wyświetli nic

Inną składnią jest użycie wyrażenia && - przydatne przy sprawdzaniu elementów szablonu:

{sidebar &&
   <div className="sidebar">
     { sidebar }
   </div>
}

Więcej informacji: https://reactjs.org/docs/conditional-rendering.html

Szablon

Zobaczmy na prostym przykładzie jak można użyć JSX do stworzenia Layoutu - czyli szablonu wspólnego dla kilku stron. Na stronie umieszczamy “sidebar” menu oraz obszar treści:

import React from 'react';

export default class Layout extends React.Component{
 render() {
  let {navigation, header, sidebar, content,
       company, path, ...other} = this.props;
  if (sidebar) {
   return (
     <div {...other}>
         <div className="container-fluid">
             { navigation && navigation(path) }
             { header && header() }
             <div className="row">
                 <div className="col-md-8">
                     { content }
                 </div>
                 <div className="col-md-4">
                     { sidebar }
                 </div>
             </div>
         </div>
         <div className="footer">
             <p>Copyright (c) 2018</p>
         </div>
     </div>   );
  } else {
    return (
      <div {...other}>
          <div className="container-fluid">
              { navigation && navigation(path) }
              { header && header() }
              <div className="row">
                  <div className="col-md-12">
                      { content }
                  </div>
              </div>
          </div>
          <div className="footer">
              <p>Copyright (c) 2018</p>
          </div>
      </div>    );
  }
 }
}

Widzimy tutaj użycie zmiennych i funkcji przekazywanych w postaci pól obiektu props. Dzięki mechanizmowi rozpakowywania struktur możemy sprawdzić, czy odpowiednie pola w strukturze są zdefiniowane i na tej podstawie wyrenderować stronę.

A oto przykład użycia takiego szablonu:


import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, withRouter }
  from 'react-router-dom';
import 'App.css';

import Layout  from './layout';

export let Header = (props) => (
<div className="jumbotron">
</div>
);

class Sidebar extends Component {
 render = () => <div>dodatkowe informacje ...</div>
}

class Content extends Component {
  render() {
    if (this.props.location.pathname==='/')
      return (
     <div>
       <h2>Strona główna</h2>
     </div>
      );
    if (this.props.location.pathname==='/about')
        return (
         <div>autor: Jerzy Wawro, dla fundacji Galicea</div>
        );
    return('');
  }
}

Content = withRouter(Content);

export default class App extends Component {

  constructor(props, context) {
    super(props, context);
    this.state = { selected : '/'};
  }

  select = (path) => { 
    if (this.state.selected !== path) {
      this.setState({...this.state, selected: path}); 
    }
  }

  navigation = (path) => {
   return (
     <nav className="navbar navbar-default navbar-static-top">
         <div className="container">
             <ul className="nav">
                 <li className="nav-item">
                     <Link
                       className="nav-link active"
                       to="/">Home</Link>
                 </li>
                 <li>
                     <Link
                       className="nav-link disabled"
                       to="/about">About</Link>
                 </li>
             </ul>
         </div>
     </nav>
  );
 }

 render() {
  let sidebar = <Sidebar />;
  let content = <Content selected={this.state.selected}/>;
  return(
    // ROUTER OBEJMUJE CAŁY LAYOUT!!
    <Router>    
   <Layout navigation = {this.navigation}
   sidebar = { sidebar }
   content = { content }
   header = { Header }
   path = { this.state.selected }
   title = "Test"
   company = {this.props.company}
   className = "page"
  />
    </Router>
  )
 }
}

Zobacz przykład: [031]