JSX & React introduction

Introduction

Names:

React / React.js or React JS 

 

 

A JavaScript library for building user interfaces.

React JS !== React Native

Introduction

History

 

Initial release: May 2013

 

   Created by Jordan Walke

at Facebook.

 

 

Introduction

Current state: 16.8.6 (March 27, 2019)

Used by:

 

 

 

 

 

 

Introduction

Hello-World example:

 

 

 

 

 

 

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('app')
);

JSX

JavaScript XML / JavaScript Syntax Extension

Extension of the common JavaScript grammar for React

 

JSX is not valid JavaScript so it needs to be compiled to be browser conformant

Example:

const heading = <h1>This is JSX</h1>;

JSX

In React the render logic is coupled with UI logic so it explains:

  • How events get handled
  • How state is changed 
  • How data is rendered

⇒ loosely coupled units called "components" *

Example:

const Nav = () => (
  <ul id="nav">
    <li><a href="#">item1</a></li>
    <li><a href="#">item2</a></li>
  </ul>
);

*Components will be explained later

JSX

JSX needs to be compiled to JavaScript to be executable by a browser

Example:

const Nav = () => React.createElement("ul", {
  id: "nav"
}, React.createElement("li", null, React.createElement("a", {
  href: "#"
}, "item1")), React.createElement("li", null, React.createElement("a", {
  href: "#"
}, "item2")));
const Nav = () => (
  <ul id="nav">
    <li><a href="#">item1</a></li>
    <li><a href="#">item2</a></li>
  </ul>
);

Will be compiled to:

JSX

If you don't want to use JSX give this projects a try:

JSX-Expressions

Render a variable using curly braces {}

const name = 'Axel Forstenhäusler';
const element = <h1>Hello, {name}!</h1>;

ReactDOM.render(
  element,
  document.getElementById('app')
);

// Expected output: Hello, Axel Forstenhäusler!

JSX-Expressions

all valid JavaScript expressions are available
(+,-,*, ...)

 

const formatName = ({ firstname, lastname }) => `${firstname} ${lastname}`;

const user = {
  firstName: 'Axel',
  lastName: 'Forstenhäusler'
};

const element = (
  <h1>Hello, {formatName(user)}!</h1>
);

ReactDOM.render(
  element,
  document.getElementById('root')
);

// Expected output: Hello, Axel Forstenhäusler!

JSX-Expressions

Since JSX is basically JavaScript you can use all methods, statements and operators like .map, if, ternary, etc.

const getGreeting = (user) => {
  if (user) return <h1>Hello, {formatName(user)}!</h1>;
  return <h1>Hello, Stranger.</h1>;
}

JSX-Attributes

Use quotes to specify string literals as attributes:

const button = <button tabIndex="0">Click!</button>;

Use curly braces to embed JavaScript expressions in an attribute/prop

const image = <img src={avatarUrl} alt="avatar" />;

React DOM: camelCase property naming convention instead of HTML attribute names

For example:

class becomes className

tabindex becomes tabIndex

List rendering

In JSX you just loop over the array and return the JSX you want to render:

const persons = [
  'Axel',
  'Christophe',
  'Immanuel',
  'Sebastian',
];

const App = () => persons.map(person => <p>{person}</p>);


// Expected result:
// Axel
// Christophe
// Immanuel
// Sebastian

Components

Components

Like other frameworks React is based on  components.

Therefore the application consists of logically separated and reusable units.

There are two different types of components in React:

  • functional components

  • class components

Components - differences

Functional components:

const Welcome = ({ name }) => <h1>Hello, {name}!</h1>;

These are called "functional component" because they are literal JavaScript functions.

They also cannot have state or access

class Welcome extends React.Component {
  render() {
    const { name } = this.props;
    return <h1>Hello, {name}</h1>;
  }
}

Class components:

These may have state and may access component lifecycle hooks as well.

State

State repressents a component's data. A component is able to modify its state by itself. State may also be passed to child components using props.

class App extends React.Component {
  state = {
    message: 'Hello I am a state message!',
  };

  handleClick = () => {
    const { message } = this.state;
    const newMessage = message.split('').reverse().join('');
    this.setState({ message: newMessage });
  }

  render() {
    const { message } = this.state;
    return (
      <div>
        <h1>{message}</h1>
        <button onClick={this.handleClick}>Reverse message</button>
      </div>
    );
  }
}

Modifying State

You may modify a component's state using events and corresponding handler functions.

class App extends React.Component {
  state = {
    message: 'Hello I am a state message!',
    value: '',
  };

  handleClick = () => {
    const { message } = this.state;
    this.setState({ message: message.split('').reverse().join('') });
  }

  handleChange = (e) => {
    this.setState({ value: e.currentTarget.value });
  }

  render() {
    const { message, value } = this.state;
    return (
      <div>
        <p>{message}</p>
        <button onClick={this.handleClick}>Reverse message</button>
        <p>{value}</p>
        <input type="text" value={value} onChange={this.handleChange} />
      </div>
    );
  }
}

State

Things to remember about state in React:

Do not modify state directly (make local copies and use setState):

handleClick = () => {
  const { data } = this.state;
  data = `I modify ${data} now.`;
  this.setState({ data });
}

Remember that setState is async!

Components - Props

"Props" stands for properties.

Using props we may pass data from a parent to a child component.

const Parent = () => <Child content="I got passed by the parent"/>;

const Child = ({ content }) => (
  <>
    <h3>I render the passed data:</h3>
    <p>{content}!</p>
  </>
);

// Expected result: 
// I render the passed data:
// I got passed by the parent!

The child component may not modify the prop data. To do that it has to emit an event to the parent which will modify it according to its business logic.

Components

Components can refer to other components

Example: an App component which renders several Welcome components

const Welcome = ({ name }) => <h1>Hello, {name}!</h1>;

const App = () => (
  <>
    <Welcome name="Axel" />
    <Welcome name="Christophe" />
    <Welcome name="Immanuel" />
  </>
);

// Expected output:
// Hello, Axel!
// Hello, Christophe!
// Hello, Immanuel!

Conditional rendering

There are multiple ways to render JSX conditionally:

const IfExample = () => {
  if (trueStatement) return <h1>True case</h1>;
  return <h1>False case</h1>;
}

const InlineExample = () => trueStatement ? <h1>True case</h1> : <h1>False case</h1>;

const OnlyTrue = () => (
  <>
    {unreadMessages.length > 0 &&
      <h2>You have {unreadMessages.length} unread messages.</h2>
    }
  </>
);

Components

Usually React applications have an App component as their entry point.

 

Splitting business logic into small reusable components is recommended.

Routing - Router

To enable routing in React you need to wrap your app between one of five router components:

import { BrowserRouter, HashRouter, MemoryRouter, Router, StaticRouter } from 'react-router';

BrowserRouter: Uses HTML5 history API (/newsfeed)

HashRouter: Uses a hash portion of the URL (#/newsfeed)

MemoryRouter: Keeps URL in memory (useful for Native)

Router: Low-level interface for other router components

StaticRouter: Never changes its location (server side rendering)

Routing - Route

The Route component defines which component should be rendered matching the URL.

Route parameters can be accessed through a prop.

import { Route, Redirect, Link } from 'react-router-dom';
<Route path="/news" component={News} />
<Route path="/users" exact component={ProfileList} />
<Route path="/users/:id" component={SingleProfile} />

Routing - Link

A Link component defines a link which leads to a route.

import { Route, Redirect, Link } from 'react-router-dom';
<Link to="/news">Navigate to newsfeed</Link>

Routing - Redirect

A Redirect component is used to lead the user somewhere else.
For example after a successful login redirect the user to the newsfeed

import { Route, Redirect, Link } from 'react-router-dom';
<Redirect to="/news" />

React & GraphQL

Packages

To use GraphQL together with React we will use the React Apollo Client.

What we need:

Apollo Boost: helps setting up an Apollo Client

React Apollo: View layer intergration of Apollo Client for React

GraphQL Tag: Parsing the GraphQL queries

Get started

Create a client:

import ApolloClient from 'apollo-boost';
import { gql } from 'graphql-tag';
import { ApolloProvider } from 'react-apollo';
const App = () => (
  <ApolloProvider client={client}>
    ... Your app here
  </ApolloProvider>
);
const client = new ApolloClient({
  uri: '<your-url>',
});

Connect yout client to React:
To access Apollo's features you need to wrap your app into the ApolloProvider:

Now we are ready to use!

Get started

Create a client:

import ApolloClient from 'apollo-boost';
import { ApolloProvider } from 'react-apollo';
const App = () => (
  <ApolloProvider client={client}>
    ... Your app here
  </ApolloProvider>
);
const client = new ApolloClient({
  uri: '<your-url>',
});

Connect yout client to React:
To access Apollo's features you need to wrap your app into the ApolloProvider:

Request data

To request data we use the Query component of react-apollo:

const GET_PLANTS = gql`
  {
    plants {
      name
      type
    }
  }
`;
import gql from 'graphql-tag';
import { Query } from 'react-apollo';

After that we write our query using graphql-tag:

Pass the query to the Query component and render the response data:

<Query query={GET_PLANTS} fetchPolicy="network-only">
  {({ loading, error, data }) => {
    if (loading) return 'Loading...';
    if (error) return `Error! ${error.message}`;

    return data.plants.map(({ name, type }) => (
      <div key={name}>
        <p>Name: {name}</p>
        <p>Type: {type}</p>
      </div>
    ));
  }}
</Query>

Request specific data

const GET_PLANT = gql`
  query Plant($name: String!) {
    plants(where: { name: $name }) {
      type
      size
    }
  }
`;

To request specific data we need to define the query differently. GraphQL also checks whether the passed variable is of the correct type (in this case String).

Using the Query component we can pass a variables object:

<Query query={GET_PLANT} variables={{ name: 'ivy' }} fetchPolicy="network-only">
  {({ loading, error, data }) => {
    if (loading) return 'Loading...';
    if (error) return `Error! ${error.message}`;
    const [{ type, size }] = data.plants;

    return (
      <>
        <p>Type: {type}</p>
        <p>Size: {size}</p>
      </>
    )
  }}
</Query>

Mutate data 1

For all kinds of mutations Apollo provides a Mutation component:

const CREATE_PLANT = gql`
  mutation CreatePlant(
    $name: String!
    $type: String!
    $size: Int!
  ) {
    createPlant(data: {
      name: $name
      type: $type
      size: $size
    }) {
      name
    }
  }
`;
import gql from 'graphql-tag';
import { Mutation } from 'react-apollo';

We define the mutation using graphql-tag again:

Mutate data 2

<Mutation mutation={ADD_TODO} ignoreResults>
  {createPlant => (
    <form
      onSubmit={e => {
        e.preventDefault();
        createPlant({ variables: { name: name.value, type: type.value, size: size.value } });
      }}
    >
      <input ref={node => name = node} type="text" placeholder="Name"/>
      <input ref={node => type = node} type="text" placeholder="Type"/>
      <input ref={node => size = node} type="number" placeholder="Size"/>
      <button type="submit">Add plant</button>
    </form>
  )}
</Mutation>

Now we can pass the GraphQL statement to the Mutation component. We mutate data using a form and the React onSubmit handler.

We get the values from the inputs and pass them to the GraphQL statement:

Wrap up

Copy of React

By Axel Forstenhäusler

Copy of React

  • 219