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]