JSX = Templatesprache von React
<div>
, <img>
, <MyComponent>
)wir können Zahlen und Strings als grundlegende Typen direkt einbinden:
const dateString = new Date().toLocaleDateString();
<div>curent date: {dateString}</div>
Der Wechsel von XML auf JS klappt auch bei Properties:
<a href={'https://en.wikipedia.org/wiki/' + articleName}>
wikipedia article
</a>
Beachte die fehlenden Anführungszeichen bei href
Steht eine Property in Anführungszeichen, haben die geschweiften Klammern keine besondere Bedeutung:
<a href="https://google.com/search?q=what+is+${}+in+js">
google search
</a>
setzen von booleschen HTML-Properties:
<button disabled>disabled button</button>
oder
<button disabled={true}>disabled button</button>
Manche Properties von Elementen haben andere Namen als in standard HTML (spiegeln standard DOM-Properties wider)
className
(anstatt class
)htmlFor
(anstatt for
)in HTML sind die folgenden Beispiele äquivalent (und enthalten je ein Leerzeichen zwischen den Bildern):
<img src="foo.png" /> <img src="bar.png" />
<img src="foo.png" /> <img src="bar.png" />
<img src="foo.png" />
<img src="bar.png" />
in JSX gilt:
Einzelnes Leerzeichen:
<img src="foo.png" /> <img src="bar.png" />
Kein Leerzeichen:
<img src="foo.png" />
<img src="bar.png" />
"Erzwungenes" Einfügen eines Leerzeichens in JSX:
<p>
long multi-line text where spaces{' '}
<strong>are wanted</strong>
</p>
Sonderzeichen wie <
können mittels JavaScript eingefügt werden:
<p>
if a {'<'} max {'&'} a {'>'} min then ...
</p>
Kommentare können als JavaScript-Kommentare geschrieben werden:
<div>Hello World!{/* this is a comment */}</div>
Erlauben es einer Komponente, mehrere Elemente zurückzugeben (anstatt eines einzelnen Elements)
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
In React-Projekten sind Style-Definitionen üblicherweise nahe bei den betroffenen Komponenten-Definitionen zu finden
Möglichkeiten:
Styling in CSS-Dateien: typischerweise separate CSS-Datei für jede Komponente:
Einbinden von CSS-Deklarationen im Bundle:
// in TodoItem.js
import './TodoItem.css';
mögliche Struktur von CSS-Klassen via BEM: Blocks, Elements, Modifiers
<li
className={
isCompleted
? 'TodoItem TodoItem--Completed'
: 'TodoItem'
}
>
<span className="TodoItem__Title">...</span>
<input className="TodoItem__Checkbox" />
...
</li>
Werkzeuge, die bei Stylesheets hilfreich sein können:
CSS-in-JS: Stile werden in JavaScript definiert
Möglichkeiten:
style
-Property (Nachteile: keine Media-Queries, kein Autoprefixing, ...)In JSX weisen wir der style-Property ein Objekt zu, z.B.:
const containerStyle = {
display: 'flex',
justifyContent: 'center',
};
const imageStyle = {
display: 'block',
};
<h1>Slideshow image {img}</h1>
<div style={containerStyle}>
<button>prev</button>
<img style={imageStyle} src="..." alt="..." />
<button>next</button>
</div>
einfaches Beispiel mit der Library emotion:
import { css } from '@emotion/css';
<div
className={css({
display: 'flex',
justifyContent: 'center',
})}
>
...
</div>
Übung: Füge (weiteres) Styling zur Bilder-Slideshow hinzu
Möglichkeiten, um if / else in JSX zu verwenden:
?
) im Templateinline-Bedingung:
<div>
<h1>Foo Game</h1>
{gameActive ? (
<div>score: {score}</div>
) : (
<div>Game over. Final score: {score}</div>
)}
</div>
if / else Statement vor dem Template:
let statusMessage;
if (gameActive) {
statusMessage = <div>score: {score}</div>;
} else {
statusMessage = (
<div>Game over. Final score: {score}</div>
);
}
return (
<div>
<h1>FooGame</h1>
{statusMessage}
</div>
);
mehrere return-Statements:
if (gameActive) {
return (
<div>
<h1>FooGame</h1>
<div>score: {score}</div>
</div>
);
} else {
return (
<div>
<h1>FooGame</h1>
<div>Game over. Final score: {score}</div>
</div>
);
}
if - ohne else:
<div>{isError ? <div>{errorMessage}</div> : null}</div>
möglichere kürzere Version:
<div>{isError && <div>{errorMessage}</div>}</div>
Der Operator &&
in JavaScript:
true && 'my message'; // 'my message'
false && 'my message'; // false
Die Werte true
und false
werden in JSX nicht dargestellt (genauso wie null
)
Übung: In der Slideshow, verstecke Buttons, die nicht angeklickt werden können (z.B. den previous-Button wenn der Benutzer beim ersten Bild ist)
Mehrere Elemente können via Arrays eingebunden werden:
const elements = [
<li>foo</li>,
<li>bar</li>,
<li>baz</li>,
];
<h1>three elements</h1>
<ul>
{elements}
</ul>
Beispiel: Auflisten aller Einträge des React-Objekts
Codesandbox: https://codesandbox.io/s/react-api-list-tjq60t?file=/src/ReactApiList.tsx
import * as React from 'react';
const reactApi = [];
for (let entry in React) {
reactApi.push(<li>{entry}</li>);
}
<div>
List of React API entries:
<ul>{reactApi}</ul>
</div>
oft werden wiederholte Elemente aus Arrays von Daten via .map
erstellt:
const initialTodos = [
{ id: 1, title: 'groceries', completed: false },
{ id: 2, title: 'cooking', completed: true },
{ id: 3, title: 'gardening', completed: false },
];
function TodoApp() {
const [todos, setTodos] = useState(initialTodos);
return (
<ul>
{todos.map((todo) => (
<li>{todo.title}</li>
))}
</ul>
);
}
Bei obigem Code:
Warnung in der Browser-Konsole (Wegen Effizienz)
Lösung: key:
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
Übung: für die Slideshow, erstelle kleine Vorschaubilder für 5 Bilder (2 vorhergehende, aktuelles, 2 folgende)
Hinweise: möglicher Code, um Vorschau-IDs zu generieren:
const previewIds = [];
for (let i = img - 2; i <= img + 2; i++) {
if (i >= 0) {
previewIds.push(i);
}
}
function sayHello() {
alert('hello world');
}
<button onClick={() => sayHello()}>Say Hello</button>
Liste von Browser-Events:
https://www.w3schools.com/jsref/dom_obj_event.asp
Zugriff auf das Event-Objekt als Funktionsparameter:
<button
onClick={(event) => {
console.log(event);
}}
>
click me
</button>
hier wird das Event ein MouseEvent-Objekt sein
Achtung: Ein Event Handler muss eine Funktion sein, und nicht ein Funktionsaufruf
OK:
<button onClick={(event) => handleEvent(event)}>
click
</button>
OK:
<button onClick={handleEvent}>click</button>
nicht OK:
<button onClick={handleEvent()}>click</button>
Standard-Verhalten eines Submit-Events in einem Formular: Direktes Senden von Daten zum Server
Ersetzen des Standardverhaltens:
<form
onSubmit={(event) => {
event.preventDefault();
// handle submit with custom logic
}}
>
...
<button type="submit">submit</button>
</form>
Slideshow Übungen:
versuche, die kurze oder lange Notation für Event-Listeners bei verschiedenen Events zu verwenden
frage das Event-Objekt einiger Events ab und logge einige Event-Informationen
kleines Formular, um auf ein bestimmtes Bild zu wechseln: beinhaltet ein Eingabefeld für eine Bild-ID und einen go-Button
mögliches Angriffsziel am Front-End: XSS-Angriffe
XSS-Angriffe:
ein böswilliger Benutzer stellt Inhalte auf unserer Website online (z.B. in einem Post oder auf der Profilseite) - wenn andere die Website besuchen, wird der böswillige Code im Browser des jeweiligen Beutzers ausgeführt, während dieser unsere Website besucht
🙂 beim zuweisen von Inhalten werden XML-Tags automatisch escaped
der folgende Code wird nur reinen Textinhalt darstellen - er ist kein Angriffsziel:
const userAddress =
'foo <script>prompt("enter credit card number:");</script>';
<h1>profile</h1>
<p>address: {userAddress}</p>
🙁 das Attribut href bietet Angriffsziele:
const userWebsite =
'javascript:prompt("enter credit card number:");';
<h1>profile</h1>
<p>address: {userAddress}</p>
<p><a href={userWebsite}>website</a></p>
mögliche Lösung: stelle sicher, dass User-generierte externe URLs mit http:// oder https:// beginnen
siehe auch: Artikel auf pragmaticwebsecurity.com, Artikel von Ron Perris, React pull request mit mehr Details
XML-Elemente werden kompiliert zu Aufrufen von:
_jsx()
(ab React 17)React.createElement()
(React 16 - React
muss importiert sein, um JSX zu schreiben)const element = <a href="https://google.com">Google</a>;
wird kompiliert zu:
const element = _jsx(
'a',
{ href: 'https://google.com' },
'Google'
);
const element = (
<MyComponent prop1={1} prop2={2}>
<div>test 1</div>
<div>test 2</div>
</MyComponent>
);
wird kompiliert zu:
const element = _jsx(
MyComponent,
{ prop1: 1, prop2: 2 },
_jsx('div', null, 'test 1'),
_jsx('div', null, 'test 2')
);