JSX = template language of React
<div>
, <img>
, <MyComponent>
)we can include numbers and strings as basic types:
const dateString = new Date().toLocaleDateString();
<div>curent date: {dateString}</div>
we can change from XML to JS for an entire property:
<a href={'https://en.wikipedia.org/wiki/' + articleName}>
wikipedia article
</a>
Note: no quote characters around the value of href
If a prop is enclosed in quotes, the curly braces have no special meaning
<a href="https://google.com/search?q=what+is+${}+in+js">
google search
</a>
setting boolean HTML properties:
<button disabled>disabled button</button>
or
<button disabled={true}>disabled button</button>
Some element properties have different names than in HTML (reflecting standard DOM properties)
className
(instead of class
)htmlFor
(instead of for
)In HTML the following examples are equivalent (displaying a single space between the images):
<img src="foo.png" /> <img src="bar.png" />
<img src="foo.png" /> <img src="bar.png" />
<img src="foo.png" />
<img src="bar.png" />
rules in JSX:
Single space:
<img src="foo.png" /> <img src="bar.png" />
no space:
<img src="foo.png" />
<img src="bar.png" />
"force" a space in JSX:
<p>
long multi-line text where spaces{' '}
<strong>are wanted</strong>
</p>
Special characters like <
can be inserted via JavaScript:
<p>
if a {'<'} max {'&'} a {'>'} min then ...
</p>
Comments can be written as JavaScript comments:
<div>Hello World!{/* this is a comment */}</div>
Fragments enable returning multiple elements from a component / function:
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
In React, style definitions are usually located close to the component definition
possibilities:
styling in CSS files: typically separate CSS file for every component:
including CSS declarations in the bundle:
// in TodoItem.js
import './TodoItem.css';
possible structure of CSS classes via BEM: Blocks, Elements, Modifiers
<li
className={
isCompleted
? 'TodoItem TodoItem--Completed'
: 'TodoItem'
}
>
<span className="TodoItem__Title">...</span>
<input className="TodoItem__Checkbox" />
...
</li>
tooling that can help with stylesheets:
CSS-in-JS: styles are defined inside JavaScript
options:
style
-property (downsides: no media queries, no autoprefixing, ...)In JSX the style property takes an object, e.g.:
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>
simple example with the emotion library:
import { css } from '@emotion/css';
<div
className={css({
display: 'flex',
justifyContent: 'center',
})}
>
...
</div>
Exercise: Add (more) styling to the image slideshow application
options for using if / else in JSX:
?
) in the templateinline condition:
<div>
<h1>Foo Game</h1>
{gameActive ? (
<div>score: {score}</div>
) : (
<div>Game over. Final score: {score}</div>
)}
</div>
if / else statement before the 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>
);
multiple 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 - without else:
<div>{isError ? <div>{errorMessage}</div> : null}</div>
potential shorter version:
<div>{isError && <div>{errorMessage}</div>}</div>
The operator &&
in JavaScript:
true && 'my message'; // 'my message'
false && 'my message'; // false
the values true
and false
are not rendered in JSX (just like null
)
exercise: in the slideshow, hide buttons which cannot be clicked (e.g. the previous-button if the user is viewing the first image)
multiple elements may be added via arrays:
const elements = [
<li>foo</li>,
<li>bar</li>,
<li>baz</li>,
];
<h1>three elements</h1>
<ul>
{elements}
</ul>
example: listing all entries in the react package
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>
typically, repeated elements are created from arrays of data via .map
:
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>
);
}
With the above code:
warning in the browser console (concerning efficiency)
solution: key:
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
exercise: for the slideshow, create small previews for 5 images (2 previous, current, 2 upcoming)
hint: example code for creating preview ids:
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>
list of browser events: https://www.w3schools.com/jsref/dom_obj_event.asp
accessing the event object as a function parameter:
<button
onClick={(event) => {
console.log(event);
}}
>
click me
</button>
here the event will be a MouseEvent object
note: an event handler must be a function, not a function call
OK:
<button onClick={(event) => handleEvent(event)}>
click
</button>
OK:
<button onClick={handleEvent}>click</button>
not OK:
<button onClick={handleEvent()}>click</button>
Default behavior of a submit event in a form: directly send data to the server
Replacing the default behavior:
<form
onSubmit={(event) => {
event.preventDefault();
// handle submit with custom logic
}}
>
...
<button type="submit">submit</button>
</form>
slideshow exercises:
try using the short or long notation for event listeners on different events
get the event object of some event and log some event details
small form to go to a specific image: has an input field to enter an image ID and a go button
potential threat on the front-end: XSS attacks
XSS attacks:
a malicious user submits some content to our website (e.g. in a post or on their profile page) - when other users visit the site, the malicious code will be executed in the other user's browser while visiting our website
🙂 when binding content, XML tags will be escaped automatically
the following code will just display plain text content - it is not an attack target:
const userAddress =
'foo <script>prompt("enter credit card number:");</script>';
<h1>profile</h1>
<p>address: {userAddress}</p>
🙁 the attribute href does offer attack targets:
const userWebsite =
'javascript:prompt("enter credit card number:");';
<h1>profile</h1>
<p>address: {userAddress}</p>
<p><a href={userWebsite}>website</a></p>
possible solution: make sure user-supplied external URLs start with http:// or https://
see also: article on pragmaticwebsecurity.com, article by Ron Perris, React pull request with more details
XML elements are compiled to calls of:
_jsx()
(React 17 and above)React.createElement()
(React 16 - React
must be imported when writing JSX)const element = <a href="https://google.com">Google</a>;
compiles to:
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>
);
compiles to:
const element = _jsx(
MyComponent,
{ prop1: 1, prop2: 2 },
_jsx('div', null, 'test 1'),
_jsx('div', null, 'test 2')
);