ReactJS for building UI
Intro
ReactJS, or simply React, is an open-source JavaScript library for building fast and interactive user interfaces i.e. front-end of web applications. React takes care of rendering view (putting page on the screen) and making sure the view is in sync with the state (data values). We can be getting a state from an external API or we can apply additional frameworks for routing and calling HTTP requests (Flask, Django) to server database.
ReactJS basics:
- Basic element is a Component - a piece of UI.
- When building application we build a bunch of independent, isolated and reusable components.
- Every application has at least one component - the root component.
- Root component contains child components making user interface a tree of components.
- Component can be either a class or a function.
Document Object Model:
- React receives data coming from database or external API and renders it into Document Object Model (DOM).
- DOM is cross-platform and language-independent interface for XML or HTML documents.
- in other words, DOM is an object oriented representation of XML/HTML document,
- DOM structures XML/HTML into logical tree consisted of nodes where each node constitutes an object representing a part of document,
- e.g. <tittle> is a single node of parent node <head> in HTML document,
- DOM has methods that allow accessing three's elements programmatically,
- those methods enable us to interfere document structure, changing style or content of an element,
- nodes also have event handlers that can react on user's behaviour changing it's structure/style/content.
Virtual DOM:
- When web-page loading, the browser creates DOM which becomes the representation of web-page's HTML document.
- React copies and keeps a lightweight in-memory represenation of browser's DOM which we refer to as the virtual DOM .
- Browser's DOM stays in sync with virtual DOM by a library such as ReactDOM. This process is called reconciliation.
- When code rendered in React, the otput is a JS object called React Element that maps to a virtual DOM Element:
1. State of component changes.
2. We get a new React element in virtual DOM.
3. React compares the element with state of a previous one.
4. React figures what has been changed.
5. React updates a part of real DOM so that it can be in sync with virtual DOM. - React = reacts to state changes.
- In that way, we don't have to work with real browser's DOM rendering all page each time some element gets updated, react updates only one specific element which change concerns.
- That solution allows making dynamic actions on web-page:
- adding/removing HTML elements or their attributes,
- changing CSS styles,
- reacting to events and creating new ones.
ReactJS with DOM:
- ReactJS uses JavaScript XML (JSX) which allows us to write HTML elements into React's code and place them into DOM without any additional methods like createElement().
- instead of writingReact.createElement(div)
we can simply type<div>
. - To get UI layout from JSX code, it needs to be compiled by JS compiler: Babel.
1. JSX:
import React from 'react'
const element = <h1>Hello World</>
- we need to import React anyway.
2. Babel compiles JSX expression into React element,
3. React:
import React from 'react'
var element = React.createElement("h1", null, "Hello World");
- ReactJS provides a selective rendering which results with a performance boost:
- it keeps in-memory cache where each change is being computed,
- it renders only single DOM component that actually chagne instead of rendering entire page each time change is made,
- rendering selectively mens e.g. saving a lot work for recalculating CSS style and rerendering entire web page.
ReactJS structure:
- We can say that ReactJS is built with units called components:
- component is a reuseable, sigle responsibility piece of code that can be rendered many times,
- components are rerendered to a particular DOM element using React DOM library,
- during component rendering, we can pass parameters when calling it,
- we can declare component as a function or a class,
- it contains all of the JSX code, JS logic and CSS styling,
- applicaiton is built from componenets being rendered in logic sequence to the screen,
- it's a good practice to keep all the componenect in '.\components' directory e.g. '.\components\navi.jsx'. - Root component:
import React from "react";
function App() {
    return (
          <div>
               <h1>Hello React!</h1>
          </div>
    );
}
export default App;
is being rendered by ReactDOM:
import React from "react";
import ReactDOM from "react-dom";
import App from ".\App";
ReactDOM.render(<App />, document.getElementById('root'));
where root is <div> id in main index.html - file that displays UI on the screen. - Multiple elements on the same level needs to be wrapped in a parent element like <div></div> or shortly <></> or needs to be returned as an array.
<>
  <Header />
  <Content />
  <Footer />
</>
or
<div>
  <li>...</li>
  <li>...</li>
  <li>...</li>
</div>
or if we don't want to have empty div tags in HTML document:
<React.Fragment>
  <li>...</li>
  <li>...</li>
  <li>...</li>
</React.Fragment>
- We can put JS expressions inside JSX with {}:
JSX:      <h1>{1 + 2}</h1>
HTML:<h1>3</h1>
Anonymous function and arrow function:
- Anonymous function:
{users.map(function(user) {
    return <User name={user.name} surname={user.surname} />
})}
- Arrow function:
{users.map(user => {
    return <User name={user.name} surname={user.surname} />
})}
- Arrow function in one line:
{users.map(user => <User name={user.name} species={user.species} /> )}
- Arrow function with no 'return' keyword:
{users.map(user => (
    <User name={user.name} species={user.species} />
))}
Events:
- We can program what happens when for example button clicked:
import React from "react";
function App() {
    const printHello = () => {
          console.log("Hello React!")
    };
    return (
          <div>
               <button onClick="{printHello}">Hello</button>
          </div>
    );
}
export default App;
Importing components:
- We export printHello function to a separate componenet and import it into mainApp function:
import React from "react";
import Hello from ".\printHello";
function App() {
    return (
          <div>
               <Hello />
          </div>
    );
}
export default App;
Passing parameters into components:
- App.js:
import React from "react";
import Hello from ".\printHello";
function App() {
or with arrow function:const App = () => {
    return (
          <div>
               <Hello name="Artur"/>
          </div>
    );
}
export default App;
- printHello.js:
import React from "react";
function Hello(props) {
or with arrow function:const Hello = (props) => {
    const printHello = () => {
          console.log("Hello {props.name}!")
    };
    return (
          <div>
               <button onClick="{printHello}">Hello</button>
          </div>
    );
}
export default Hello;
Class component:
- So far we has been working with function components, here is how it looks like with class componenet:
import React, { Component } from 'react';
export default class Greetings extends Component {
    const nickname = 'Arturro'
    let postion = 'Specialist'
    state = {
            name: 'Artur',
            items: ['item1','item2','item3']
    };
    render() {
        return (
            <div>
                <h1>Hi {this.state.name}</h1>
or<h1>Hi {this.formatName()}</h1>
                <ul>
                    {this.state.items.map(item => <li key={item}>{item}</li>)}
                </ul>
            </div>
        )
    };
    formatName() {
            const { name } = this.state;
            return name === 'Artur' ? 'Sir' : name;
    };
}
- State is the special property in a class component that includes any data the component needs:
- constants likeconst nickname = 'Arturro'
or variables likelet postion = 'Specialist'
are rendered only once when a class component is being rendered (they do not redner real-time afterwards),
- all data being rendered real-time is wrapped in a state{} as we observe its state in the current moment,
- when variable value in state{} gets updated, it changes in every React element that uses it, even after first componend rendering,
- we can access variable in state by keyword this:
{this.state.name},
- we can modify variable in state with setState:
{this.setState{name='Arthur'}}
- Function formatName() adds a logic for returning a value.
- What we have in render() function, this is encapsulated in virtual DOM. In the class above, virtual DOM is a tree of 3 elements:
- react element:<div>
,
- 2 children:<h1>
and<ul>
- When state in some of element gets changed, react puts the new virtual DOM (new tree with change) side by side with the old virtual DOM (old tree before change). Based on the comparison, react is able to point the element in which the change happened so that it can update the responding element in a real DOM of a web-page.
Class component | Function componenet |
---|---|
Stateful | Stateless |
Declaring variable in class state{} | Declaring variable in useState hook |
Accessing variable state with this.state.variableName | Accessing variable with variableName |
Changing variable state with this.setState({title:'view'}) | Changing variable with setVariableName('New') |
Usaually used when I need to work with state that gets updated frequently | Usaually used when I don't need to be working with state |
React Hooks:
- useState - asigning a state to a variable with modifier assigned to it:
const [state, setState] = useState(initialState);
- useState returns a varaible storing local state and a function to update that variable,
- during first rendering, a value of state variable is as the same as an initially passed value of initialState variable,
- function setState is used for updating the local state id est the value of state variable,
- during next render processes, the first value in useState is alwyas the most recent state set by setState function.
- the example code:
function App() {
    const[count, setCount] = useState(0)
    const increment = () => {
          setCount(count + 1);
    };
    return (
          <div>
               <button onClick="{increment}">Add</button>
               <hi>{count}</h1>
          <div>
    );
}
export default App;
- when getting data from an external API we can save it in a state,
function App() {
    const[clients, setClients] = useState([
        {name:'Artur', surname:'Skrzeta'},
        {name:'Jan', surname:'Kowalski'},
        {name:'Jonh', surname:'Smith'}
    ]);
    return (
          <div className="app">
               {users.map(user => (
                   <Hello name={user.name} surname={user.surname} />
               ))}
          </div>
    );
}
export default App;
- useEffect from function App() component:
useEffect(() => {
    const getDataForSource = async () => {
            await fetch("https://...")
                .then((response) => response.json())
                .then((data) => {
                    const countires = data.map((country) => ({
                        name: country.country,
                        value: country.value,
                     }));
                     setCountires(countries);
 //modifier from useState
                 });
          };
          getDataForSource();
}, []);
- runs a piece of code based on a given condition,
- code within useEffect runs only once when component loads and not again after if no condition - when [] is empty,
- code within useEffect runs only once when component loads and when condition [countires] given,
- when condition [countires] given, code in useEffect runs when variable countires loads or changes.
Map function on a list of items:
- Map function allows to execute a defined function on every element of a passed list:
class ...
    state = {
        items = [
            { id: '1', title: 'Amazing product' },
            { id: '2', title: 'Nice product' },
        ]
    }
    render() {
        const items = this.state.items.map(i => {
            return <div key="{i.title}">{ i.title }</div>
        })
    }
    return <div> {elements} </div>
}
const items
takesitems
fromstate {}
using this keyword:this.state.items
- Every item from a list is mapped with a passed function that returns div element.
- Each div element needs to have an unique key assigned:
<div key="{i.title}">{i.title}</div>
Features
App includes following features:
Demo
Json-server:
- Json-server can be used as a backend prototyping REST API
- It offers all necessary methods database should have like create, updated, delete, select.
- The biggest disadvantage is lack of authentication which makes it a good tool for frontend testing but not so good to use in production.
Postman:
- Postman allows to sent requests to server.
- That way I can test out REST API resources manually.
- I can get all data from db.json by sending GET request to localhost:5000;
- when sending request to /items enpoint, server answers with items JSON.
- when sending request to /clients enpoint, server answers with clients JSON. - I can insert data into db.json by sending POST request to localhost:5000 with JSON body request.
React Admin:
<Admin>
element getsrestProvider
which is hearing tohttp://localhost:3000
<Resource />
child element accepts endpoint name and componenet that displays the API resource.- Component in
<Resource />
lists all the items available under given endpoint.
Setup
- Nodejs installation:
   https://nodejs.org/en/
      once installed, we get access to node package manager (npm) - Npx installation:
   npm install -g npx
   npx --version
- Creating package.json in current directory:
   npm init -y
     add to package.json:
   "scripts": {
         "server": "json-server --watch db.json --port 5000 --middleware
               ./range.js",
         "client": "npm start --prefix client",
         "dev": "concurrently \"npm run server\" \"npm run client\""
      },
- Json-server installation:
   npm i json-server
- Being able to run json-server and react server in one terminal at once:
   npm i concurrently
- Creating project in project directory:
   npx create-react-app client
   cd client
      adding proxy of
   client > package.json > "proxy": "http://localhost:5000"
- react-admin inatllation in client directory:
   npm i react-admin
- ra-data-simple-rest inatllation in client directory:
   npm i ra-data-simple-rest
- Material-UI inatllation in client directory:
   npm install @material-iu/core
- Bootstrap installation:
   npm i bootstrap@4.1.1
   index.js -> import 'bootstrap/dist/css/boostrap.css';
- Running react on localhost:3000 and json-server on localhost:5000:
   npm run dev