# full-stack-with-react-and-spring-boot **Repository Path**: laodasbch/full-stack-with-react-and-spring-boot ## Basic Information - **Project Name**: full-stack-with-react-and-spring-boot - **Description**: Your First Full Stack Application with React and Spring Boot - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-12-23 - **Last Updated**: 2020-12-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README README

Your First Full Stack Application with React and Spring Boot

Take your first steps towards becoming a Full Stack Developer with React and Spring Boot

React is a one of the most popular front end view frameworks - Components - JSX - State - Props

In combination with other libraries, React helps in doing a wide variety of front end features - Forms Handling - Routing System - HTTP Requests

Spring Boot is an awesome framework to build RESTful API and Microservices.

In this course, lets combine these awesome frameworks to create your first full stack web application.

References

Installation Guides

Required Tools

Installing Node Js (npm) & Visual Studio Code

Installing Java, Eclipse & Embedded Maven

Troubleshooting Installations

Getting Started with Spring, Spring Boot and JPA

Course Overview

Introduction

Developing your first full stack application with React and Spring Boot is fun.

In this course, you will learn the basics of full stack development developing a Basic Todo Management Application using React, Spring Boot and Spring Security Frameworks.

You will build the application step by step - in more than 50 steps. This course would be a perfect first step as an introduction to React and Full Stack Development.

You will be using React (Frontend View Framework), React Create App(To create React project), Various JavaScript Libraries (Axios, Formik, React Router), Spring Boot (REST API Framework), Spring (Dependency Management), Spring Security (Authentication and Authorization - Basic and JWT), BootStrap (Styling Pages), Maven (dependencies management), Node (npm), Visual Studio Code (JavaScript IDE), Eclipse (Java IDE) and Tomcat Embedded Web Server. We will help you set up each one of these.

What You will learn

Requirements

Step Wise Details

Quick Overview

Getting Hands on With React

Introduction to Web Services and REST

Getting Up and Running with REST and Spring Boot

Connecting React Frontend to Spring Boot Restful Services

Implementing Spring Security with Basic Authentication

Connecting Spring Security with JWT

Connecting REST API With JPA and Hibernate

Spring Boot in 10 Steps

First 10 Steps in JPA with H2 in-memory database

for file in *; do mv "${file}" "${file//-/ }"; done
for file in *; do mv "${file}" "${file//   / - }"; done
for file in *; do mv "${file}" "${file//01 Step/Step}"; done

Code Snippets

Core JWT Components

jwt.signing.key.secret=mySecret
jwt.get.token.uri=/authenticate
jwt.refresh.token.uri=/refresh
jwt.http.request.header=Authorization
jwt.token.expiration.in.seconds=604800

package com.in28minutes.todoservices.jwt;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class JwtInMemoryUserDetailsService implements UserDetailsService {

  static List<JwtUserDetails> inMemoryUserList = new ArrayList<>();

  static {
    inMemoryUserList.add(new JwtUserDetails(1L, "in28minutes",
        "$2a$10$3zHzb.Npv1hfZbLEU5qsdOju/tk2je6W6PnNnY.c1ujWPcZh4PL6e", "ROLE_USER_2"));
  }

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    Optional<JwtUserDetails> findFirst = inMemoryUserList.stream()
        .filter(user -> user.getUsername().equals(username)).findFirst();

    if (!findFirst.isPresent()) {
      throw new UsernameNotFoundException(String.format("USER_NOT_FOUND '%s'.", username));
    }

    return findFirst.get();
  }

}


@Component
public class JwtTokenAuthorizationOncePerRequestFilter extends OncePerRequestFilter {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private UserDetailsService jwtInMemoryUserDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.http.request.header}")
    private String tokenHeader;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        logger.debug("Authentication Request For '{}'", request.getRequestURL());

        final String requestTokenHeader = request.getHeader(this.tokenHeader);

        String username = null;
        String jwtToken = null;
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtTokenUtil.getUsernameFromToken(jwtToken);
            } catch (IllegalArgumentException e) {
                logger.error("JWT_TOKEN_UNABLE_TO_GET_USERNAME", e);
            } catch (ExpiredJwtException e) {
                logger.warn("JWT_TOKEN_EXPIRED", e);
            }
        } else {
            logger.warn("JWT_TOKEN_DOES_NOT_START_WITH_BEARER_STRING");
        }

        logger.debug("JWT_TOKEN_USERNAME_VALUE '{}'", username);
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.jwtInMemoryUserDetailsService.loadUserByUsername(username);

            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }

        chain.doFilter(request, response);
    }
}


@Component
public class JwtTokenUtil implements Serializable {

  static final String CLAIM_KEY_USERNAME = "sub";
  static final String CLAIM_KEY_CREATED = "iat";
  private static final long serialVersionUID = -3301605591108950415L;
  private Clock clock = DefaultClock.INSTANCE;

  @Value("${jwt.signing.key.secret}")
  private String secret;

  @Value("${jwt.token.expiration.in.seconds}")
  private Long expiration;

  public String getUsernameFromToken(String token) {
    return getClaimFromToken(token, Claims::getSubject);
  }

  public Date getIssuedAtDateFromToken(String token) {
    return getClaimFromToken(token, Claims::getIssuedAt);
  }

  public Date getExpirationDateFromToken(String token) {
    return getClaimFromToken(token, Claims::getExpiration);
  }

  public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
    final Claims claims = getAllClaimsFromToken(token);
    return claimsResolver.apply(claims);
  }

  private Claims getAllClaimsFromToken(String token) {
    return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
  }

  private Boolean isTokenExpired(String token) {
    final Date expiration = getExpirationDateFromToken(token);
    return expiration.before(clock.now());
  }

  private Boolean ignoreTokenExpiration(String token) {
    // here you specify tokens, for that the expiration is ignored
    return false;
  }

  public String generateToken(UserDetails userDetails) {
    Map<String, Object> claims = new HashMap<>();
    return doGenerateToken(claims, userDetails.getUsername());
  }

  private String doGenerateToken(Map<String, Object> claims, String subject) {
    final Date createdDate = clock.now();
    final Date expirationDate = calculateExpirationDate(createdDate);

    return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(createdDate)
        .setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact();
  }

  public Boolean canTokenBeRefreshed(String token) {
    return (!isTokenExpired(token) || ignoreTokenExpiration(token));
  }

  public String refreshToken(String token) {
    final Date createdDate = clock.now();
    final Date expirationDate = calculateExpirationDate(createdDate);

    final Claims claims = getAllClaimsFromToken(token);
    claims.setIssuedAt(createdDate);
    claims.setExpiration(expirationDate);

    return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
  }

  public Boolean validateToken(String token, UserDetails userDetails) {
    JwtUserDetails user = (JwtUserDetails) userDetails;
    final String username = getUsernameFromToken(token);
    return (username.equals(user.getUsername()) && !isTokenExpired(token));
  }

  private Date calculateExpirationDate(Date createdDate) {
    return new Date(createdDate.getTime() + expiration * 1000);
  }
}

@Component
public class JwtUnAuthorizedResponseAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {

  private static final long serialVersionUID = -8970718410437077606L;

  @Override
  public void commence(HttpServletRequest request, HttpServletResponse response,
      AuthenticationException authException) throws IOException {
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
        "You would need to provide the Jwt Token to Access This resource");
  }
}


public class JwtUserDetails implements UserDetails {

  private static final long serialVersionUID = 5155720064139820502L;

  private final Long id;
  private final String username;
  private final String password;
  private final Collection<? extends GrantedAuthority> authorities;

  public JwtUserDetails(Long id, String username, String password, String role) {
    this.id = id;
    this.username = username;
    this.password = password;

    List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority(role));

    this.authorities = authorities;
  }

  @JsonIgnore
  public Long getId() {
    return id;
  }

  @Override
  public String getUsername() {
    return username;
  }

  @JsonIgnore
  @Override
  public boolean isAccountNonExpired() {
    return true;
  }

  @JsonIgnore
  @Override
  public boolean isAccountNonLocked() {
    return true;
  }

  @JsonIgnore
  @Override
  public boolean isCredentialsNonExpired() {
    return true;
  }

  @JsonIgnore
  @Override
  public String getPassword() {
    return password;
  }

  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    return authorities;
  }

  @Override
  public boolean isEnabled() {
    return true;
  }

}


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class JWTWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtUnAuthorizedResponseAuthenticationEntryPoint jwtUnAuthorizedResponseAuthenticationEntryPoint;

    @Autowired
    private UserDetailsService jwtInMemoryUserDetailsService;

    @Autowired
    private JwtTokenAuthorizationOncePerRequestFilter jwtAuthenticationTokenFilter;

    @Value("${jwt.get.token.uri}")
    private String authenticationPath;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(jwtInMemoryUserDetailsService)
            .passwordEncoder(passwordEncoderBean());
    }

    @Bean
    public PasswordEncoder passwordEncoderBean() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
            .csrf().disable()
            .exceptionHandling().authenticationEntryPoint(jwtUnAuthorizedResponseAuthenticationEntryPoint).and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests()
            .anyRequest().authenticated();

       httpSecurity
            .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        httpSecurity
            .headers()
            .frameOptions().sameOrigin()  //H2 Console Needs this setting
            .cacheControl(); //disable caching
    }

    @Override
    public void configure(WebSecurity webSecurity) throws Exception {
        webSecurity
            .ignoring()
            .antMatchers(
                HttpMethod.POST,
                authenticationPath
            )
            .antMatchers(HttpMethod.OPTIONS, "/**")
            .and()
            .ignoring()
            .antMatchers(
                HttpMethod.GET,
                "/" //Other Stuff You want to Ignore
            )
            .and()
            .ignoring()
            .antMatchers("/h2-console/**/**");//Should not be in Production!
    }
}

@RestController
@CrossOrigin(origins="http://localhost:4200")
public class JwtAuthenticationRestController {

  @Value("${jwt.http.request.header}")
  private String tokenHeader;

  @Autowired
  private AuthenticationManager authenticationManager;

  @Autowired
  private JwtTokenUtil jwtTokenUtil;

  @Autowired
  private UserDetailsService jwtInMemoryUserDetailsService;

  @RequestMapping(value = "${jwt.get.token.uri}", method = RequestMethod.POST)
  public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtTokenRequest authenticationRequest)
      throws AuthenticationException {

    authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());

    final UserDetails userDetails = jwtInMemoryUserDetailsService.loadUserByUsername(authenticationRequest.getUsername());

    final String token = jwtTokenUtil.generateToken(userDetails);

    return ResponseEntity.ok(new JwtTokenResponse(token));
  }

  @RequestMapping(value = "${jwt.refresh.token.uri}", method = RequestMethod.GET)
  public ResponseEntity<?> refreshAndGetAuthenticationToken(HttpServletRequest request) {
    String authToken = request.getHeader(tokenHeader);
    final String token = authToken.substring(7);
    String username = jwtTokenUtil.getUsernameFromToken(token);
    JwtUserDetails user = (JwtUserDetails) jwtInMemoryUserDetailsService.loadUserByUsername(username);

    if (jwtTokenUtil.canTokenBeRefreshed(token)) {
      String refreshedToken = jwtTokenUtil.refreshToken(token);
      return ResponseEntity.ok(new JwtTokenResponse(refreshedToken));
    } else {
      return ResponseEntity.badRequest().body(null);
    }
  }

  @ExceptionHandler({ AuthenticationException.class })
  public ResponseEntity<String> handleAuthenticationException(AuthenticationException e) {
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage());
  }

  private void authenticate(String username, String password) {
    Objects.requireNonNull(username);
    Objects.requireNonNull(password);

    try {
      authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
    } catch (DisabledException e) {
      throw new AuthenticationException("USER_DISABLED", e);
    } catch (BadCredentialsException e) {
      throw new AuthenticationException("INVALID_CREDENTIALS", e);
    }
  }
}

public class AuthenticationException extends RuntimeException {
    public AuthenticationException(String message, Throwable cause) {
        super(message, cause);
    }
}

public class  JwtTokenRequest implements Serializable {

  private static final long serialVersionUID = -5616176897013108345L;

  private String username;
    private String password;

    public JwtTokenRequest() {
        super();
    }

    public JwtTokenRequest(String username, String password) {
        this.setUsername(username);
        this.setPassword(password);
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

public class JwtTokenResponse implements Serializable {

  private static final long serialVersionUID = 8317676219297719109L;

  private final String token;

    public JwtTokenResponse(String token) {
        this.token = token;
    }

    public String getToken() {
        return this.token;
    }
}

Course Recording Notes

#### Preview Video - Welcome to course on * in ** simple steps. - I’m Ranga Karanam. I’ve so and so much experience with … I’ve been using this framework for … - At in28minutes, we ask one question everyday - How to create more effective courses? All our success - * students on Udemy and * subscribers on Youtube - is a result of this pursuit of excellence. - You will develop * and * using * - You will learn the basics like * and move on to the advanced concepts like . - You will use - … todo … - Maven for dependency management, building and running the application in tomcat. - Eclipse IDE - All the code for this course and the step by step details are in our Github repository. - We have an awesome installation guide to help you install Maven and Eclipse. You are NOT expected to have any experience with Eclipse, Maven, or Tomcat. - What are we waiting for? Lets have some fun with * in ** steps. We had a lot of fun creating this course for you and We are confident that you will have a lot of fun. I hope you are as excited as we are to learn more. Go ahead and enroll for the course. Or take a test drive with a free preview. See you in the course.

Course Intro Video

Overview of the Github Repository

Installation of Tools Video

Each Section Introduction

Conclusion Video

Templates

Welcome Message

## ADD A FEW SAMPLE REVIEWS AFter a couple of months
## ADD A FEW SAMPLE REVIEWS - in the description of the course 

Congratulations on joining this course from in28Minutes. 

There are three things you need to understand before you start this course!

1...... Listen + See + Do Hands-on + Repeat = 90% Retention
For the first 2 hours, we repeat a few concepts to help you retain them. .

2...... Set Yourself a Goal
Set 1 hour aside every day for the next week for this course! No exceptions allowed :) 

3...... Udemy asks you for a review very early in the course! If you are not ready for giving a review, you can skip giving a review.

Thank you and enjoy the course,
Ranga From in28Minutes

Thank You for completing the course message

Congratulations on completing the course from in28Minutes.

Good Luck for your future.

Thank you ,
Ranga from in28Minutes

Bonus Lectures

TITLE : Bonus Lecture : Coupons for My Best-Selling Courses -30 Day Money Back Guarantee

I hope you enjoyed it! 

Connect and share your success (Course Completion Certificate) on Linked In - https://www.linkedin.com/in/rangakaranam/

Here are coupons for many of my best-selling courses. Please click the images/courses below to watch the course video previews (all of these courses have 30-day 100% money back guarantees):

- Copy relevant courses from https://github.com/in28minutes/learn

Other Courses

About in28Minutes

Our Beliefs

Our Approach

Troubleshooting

Rangas-MacBook-Pro:04-10-2018 rangaraokaranam$ node -v

Rangas-MacBook-Pro:04-10-2018 rangaraokaranam$ npm -v
6.4.1

#Global
npm uninstall -g React-cli
npm cache verify
npm install -g @React/cli@7.0.3

#Inside the project - If you had an earlier version of React cli
rm -rf node_modules
npm uninstall --save-dev React-cli
npm install --save-dev @React/cli@latest
npm install
- Why Visual Studio Code? - https://trends.google.com/trends/explore?date=all&q=%2Fm%2F0k2kj45,%2Fm%2F0_x5x3g,%2Fm%2F0134xwrk,%2Fm%2F0b6h18n - We use Light Theme - Install - Auto Import - Automatically finds, parses and provides code actions and code completion for all available imports. Works with Typescript and TSX - Reload to Activate

What You will Learn?

Big Picture

TypeScript and JavaScript

React Basics

Running React Applications

Automated Tests and Code Quality

Course Details

Request URLs and Examples

Common Headers

Origin - http://localhost:4200
Content-Type - application/json
Authorization 
- Bearer *** or
- Basic *****

Retrieve all todos for a user

[
  {
    id: 1,
    username: "in28minutes",
    description: "Learn to Dance 2",
    targetDate: "2018-11-09T12:05:18.647+0000",
   : false,
  },
  {
    id: 2,
    username: "in28minutes",
    description: "Learn about Microservices 2",
    targetDate: "2018-11-09T12:05:18.647+0000",
   : false,
  },
  {
    id: 3,
    username: "in28minutes",
    description: "Learn about React",
    targetDate: "2018-11-09T12:05:18.647+0000",
   : false,
  },
]

Retrieve a specific todo

{
  id: 1,
  username: "in28minutes",
  description: "Learn to Dance 2",
  targetDate: "2018-11-09T12:05:18.647+0000",
 : false,
}

Creating a new todo

{
  "username": "in28minutes",
  "description": "Learn to Drive a Car",
  "targetDate": "2018-11-09T10:49:23.566+0000",
  "done": false
}

Updating a new todo

{
  "id": 1
  "username": "in28minutes",
  "description": "Learn to Drive a Car",
  "targetDate": "2018-11-09T10:49:23.566+0000",
  "done": false
}

Delete todo

JWT Authenticate

{
  "username":"ranga",
  "password":"password@!23@#!"
}

Response

{
"token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJyYW5nYSIsImV4cCI6MTU0MjQ3MjA3NCwiaWF0IjoxNTQxODY3Mjc0fQ.kD6UJQyxjSPMzAhoTJRr-Z5UL-FfgsyxbdseWQvk0fLi7eVXAKhBkWfj06SwH43sY_ZWBEeLuxaE09szTboefw"
}

Other URLS - Refresh - http://localhost:8080/authenticate

Connection to MySQL

create sequence hibernate_sequence start with 1 increment by 1

create table todo (
    id bigint not null, 
    description varchar(255), 
    is_done boolean not null, 
    target_date timestamp, 
    username varchar(255), 
    primary key (id))

launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "Launch Chrome against localhost",
            "url": "http://localhost:4200",//Line Changed
            "webRoot": "${workspaceFolder}"
        }
    ]
}

npm install @React/material @React/cdk
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
npm install @React/flex-layout rxjs-compat

Diagrams

graph architecture {
node[style=filled,color="#59C8DE"]
//node [style=filled,color="#D14D28", fontcolor=white];
rankdir = TB;
node[shape=record]

FRONTEND[label=<React Application<BR />
   <FONT POINT-SIZE="9">Modern JavaScript - ES6</FONT>>];

REST[label=<RESTFUL API<BR />
   <FONT POINT-SIZE="9">Spring Boot on Java</FONT>>];

DB[label=<Database>];

FRONTEND -- REST -- DB
DB[shape=cylinder]
}

digraph architecture {
node[style=filled,color="#59C8DE"]
//node [style=filled,color="#D14D28", fontcolor=white];
rankdir = TB;
node[shape=record]

FRONTEND[label=<React Application<BR />
   <FONT POINT-SIZE="9">JavaScript</FONT>>];

MODULE0[label=<Components>];

MODULE1[label=<Libraries>];

COMPONENT01[label=<Login>];
COMPONENT02[label=<Logout>];
COMPONENT03[label=<ListTodo>];
COMPONENT04[label=<Todo>];
COMPONENT05[label=<Header>];
COMPONENT06[label=<Footer>];
COMPONENT07[label=<Menu>];

COMPONENT11[label=<Formik>];
COMPONENT12[label=<Axios>];
COMPONENT13[label=<ReactRouter>];

FRONTEND -> MODULE0
FRONTEND -> MODULE1

MODULE0 -> COMPONENT01
MODULE0 -> COMPONENT02
MODULE0 -> COMPONENT03
MODULE0 -> COMPONENT04
MODULE0 -> COMPONENT05
MODULE0 -> COMPONENT06
MODULE0 -> COMPONENT07

MODULE1 -> COMPONENT11
MODULE1 -> COMPONENT12
MODULE1 -> COMPONENT13

}


graph architecture {

node[style=filled,color="#59C8DE"]
//node [style=filled,color="#D14D28", fontcolor=white];
rankdir = TB;
node[shape=record]

COMPONENT[label=<Component>];

View[label=<View<BR />
   <FONT POINT-SIZE="9">JSX or Javascript</FONT>>];
Logic[label=<Logic<BR />
   <FONT POINT-SIZE="9">Javascript</FONT>>];
Styling[label=<Styling<BR />
   <FONT POINT-SIZE="9">CSS</FONT>>];
State[label=<State<BR />
   <FONT POINT-SIZE="9">Internal Data Store</FONT>>];
Props[label=<Props<BR />
   <FONT POINT-SIZE="9">Pass Data</FONT>>];

COMPONENT -- View
COMPONENT -- Logic
COMPONENT -- Styling
COMPONENT -- State
COMPONENT -- Props
}

graph architecture {

node[style=filled,color="#59C8DE"]
//node [style=filled,color="#D14D28", fontcolor=white];
rankdir = TB;
node[shape=record]

React -- Components
Components -- JSX
Components -- State
Components -- Props
React -- Features
Features -- Routing
Features -- Forms
Features -- RestAPICalls
Features -- Authentication

RestAPICalls[label=<Rest API Calls>]
Forms[label=<Forms and Validation>]

}

Todo

Next Steps

OLD Starting Up Code

Example 1

import React, { Component } from “react”; import ReactDOM from “react-dom”;

import “./styles.css”;

function App() { //Basics // No playing with DOM

// Extension //Simple React Snippets //Prettier code formatter

//JSX //babeljs.io/repl const heading = “Hello World 1”;

const element =

{heading}

;

const header =

Heading

;

const body =

Content
;

const footer =

Footer
;

const textAreaDefault = “Text Area Default Value”;

//const twoTagsAreNotAllowedAsReturn =

//React.Fragment instead of div as parent

//const allTagsShouldBeClosed =

//class vs className - https://stackoverflow.com/questions/46989454/class-vs-classname-in-react-16 //camelcase const whitespaceJSX1 =

Word1 Word2 Word3

; //Spaces consolidated to 1 const whitespaceJSX2 =

Line 1 Line 2

;

const array = [1, 2, 3];

const selectValues = [“a”, “b”, “c”];

/* function TodoExampleWithFunction() { return ‘

TodoExampleWithFunction

‘; } */

function TodoExampleWithFunction() { return

TodoExampleWithFunction

; }

class EventsComponent extends Component { constructor() { super(); this.state = { currentEvent: “” }; this.registerEvent = this.registerEvent.bind(this); } registerEvent(e) { //console.log(e.type); this.setState({ currentEvent: e.type }); } render() { return (