Search:   Dictionary All Posts
Store Your Knowledge at the Brain Bank!

Intro to React - React Basics

By Jamie in Lessons / Programming - React  12.29.18  (Source)
Summary - The very basics of React. Practice coding to increase memory retention.
Everything written here is for practice only. Docs can be found here. And the actual Scrimba practice course of everything below can be found at the source link for this article.

Create a react app
npx create-react-app cp1-frontend

Keep practicing these lessons
setState of new array using map on clicked checkbox
https://scrimba.com/p/p7P5Hd/cgDqBHP

index.html

Start with a regular HTML page with one main div in the body with an id of  'root'.

include the main js file, in this case index.js

Then, in the index.js file, append React 'components' directly to this main 'root'.

React Components

A react component is one thing. Not multiple things. It can, however, be one thing that contains many things.

The concept is organizational. Every component should be named as the function or class it will export.

index.js

In index.js file you import React and ReactDom as boilerplate. You also import your 'App.js' file which you will use to call most of your other components.

<-- Code -->
import React from 'react'
import ReactDom from 'react-dom'
import App from './App'        // react assumes files end with .js

ReactDom.render(<App />, document.getElementbyId('root'))
<-- Code -->

we leave off semicolons for a clean look, but they also can be included.

App.js  - we name components in React with capital camel case.

<-- Code -->
import React from 'react' 

function React(){
    return ( <div>Hello World</div> ) // return in paranthesis. Every component can only return one thing. So you must return one div tag, as opposed to multiple div tags and an h1 and p tag. BUT the trick here is to simply start with a div tag, then put any other kind of tags within the div tag. So you can have a div tag, then an h1, p, other divs, spans, etc. within the main div tag and it would be proper.
}

export default React
<-- Code -->

React Props (properties/parameters)

like a parameter in normal languages. In react, however, it is just one object being passed in named 'props'. the object will have any properties passed in, so technically, an object is passed in which holds the properties/parameters.

<-- Code -->
import React from 'react'

function App(props){
    return (
        <div>
            <div>{props.name}</div>
            <div>{props.age</div>
        </div>
}

<-- Code -->

Component as Class instead of Function with Props

<-- Code -->
import React from 'react'

class App extends React.Component {
    

    render(){
        return (
            <div>{this.props.propertyName}</div>
        )
    }

}

export default App

<-- Code -->

Passing in Props

<-- Code -->
import React from 'react'
import ReactDom from 'react-dom'
import App from './App'        

ReactDom.render(<App name='Ryan' age=33 />, document.getElementbyId('root'))
<-- Code -->

Passing in Props as an Object

<-- Code -->
import React from 'react'
import ReactDom from 'react-dom'
import App from './App'       

ReactDom.render(<App person={{name:'Ryan', age:33}} />, document.getElementbyId('root'))
<-- Code -->

Using Props as an Object

<-- Code -->
import React from 'react'

function App(props){
    return (
        <div>
            <div>{props.person.name}</div>
            <div>{props.
person.age</div>
        </div>
}

<-- Code -->

Mapping Data (json/database feed) as Components

Get data from a json file. Then, map each item in the feed to a component.

Then, pass the new mapped array into the main component

App.js
<-- code -->
import React from 'react'
import Product from './Product'
import productData from './productData'

function App(){

    const products = productData.map(item => <Product key = {item.id} name = {item.name} price = {item.price} />)

OR PASS AS AN OBJECT
    const products = productData.map(item => <Product key = {item.id} item = {item} />)

    return (
        <div>
            {products}
        </div>
}

export default App

</-- code -->

Product.js
<-- code -->
import React from 'react'

function Product(props){

    return (
        <div>
            <h1>{props.name}</h1>
            <p>{props.price}</p>
        </div>
    )
}

export default Product

</-- code -->

Adding JS & Styles Inline
inline styles within the JSX code must be added as if it was JS, not css, and the styles must be sent as on object, therefore, you need to start the styles with a { to indicate the start of javascript and then a { to start the object.

Product.js
<-- code -->
import React from 'react'

function Product(props){

    return (
        <div>
            <h1>{props.name}</h1>
            <p style={{display:  !props.price && 'none'  }}>{props.price}</p>
        </div>
    )
}

export default Product

</-- code -->

as a class instead of a function...

<-- code -->
import React from 'react'

class Product extends React.Component{

    render(){
        return (
            <div>
                <h1>{this.props.name}</h1>
                <p style={{display:  !this.props.price && 'none'  }}>{this.props.price}</p>
            </div>
        )
    }

}

Class Component with Constructors & Render

import React, {Component} from 'react'

class App extends Component {

    constructor(){
        super()
        this.state = {
            isLoggedIn: false
        }

    render(){
        return (
            <div>
                <h1>You are logged {this.state.isLogged ? 'in' : 'out'}</h1>
            </div>
        )
    }
}


Notes - you must call super() function first in constructor. This function brings in all the methods and properties from the class that is being extended. You cannot use 'this' without using super because this would not be referring to anything.

Handling Events
In your class you create a method that will handle the event. You pass the event as part of the props to the component that will use the event. In the component, you may pass back any id or data that the event will use.

A simple example - without passing to components, just change a button text and paragraph text depending on whether the user is logged in. Create a login/logout button depending on current conditions...

class LoginButton extends React.component {
   
    constructor(){
        super()
        this.state = {
            isLoggedIn: false
        }
        this.handleClick = this.handleClick.bind(this)
    }

    handleClick(){
        this.setState(prevState => {
            return { isLoggedIn: !prevState.isLoggedIn }
        }
    }

    render(){
        let loggedStatusText = this.state.isLoggedIn ? 'You are logged in!' :  'You are not logged in!'
        let loggedButtonText = this.state.isLoggedIn ? 'Logout!' :  'Login!'
        return (
            <div>
                <p>{loggedStatusText}</p>
                <button onClick={this.handleClick}>{loggedButtonText}</button>
            </div>
        )
    }

}


this & this.setState ---- on an event, in order to change state you have to use the this.setState() built-in React function.  be sure the method this.setState is in has a bound this keyword by either binding this explicitly in the constructor or by simply making the method an arrow function instead of a defined function...

class App extends Constructor {

    constructor(){
        this.state = { isLoggedIn: false }
    }

   handleClick = (e) => {
        e.preventDefault()
        this.setState({ isLoggedIn: true })
    }

    render(){
        return (
            <div>
                <div>{isLoggedIn ? 'You are logged in!' : 'You are NOT logged in!'}</div>
                <button onClick={this.handleClick}>{isLoggedIn ? 'Logout' : 'Login'}</button>
            </div>
        )
    }

}
    


you must pass in an object to this.setState() - you will be resetting the state of this, which is an object.


Changing data found in an array...  Let's say there is a checkbox you want to change. You start with its default state, which is received from the initial array. Then, someone clicks on the checkbox, which triggers the 'onChange' event. The id of the clicked on thing is sent back to the event handler. The event handler sets a new state of the array. This is important to understand... you should not update the previous state, you are creating a new state and saving the entire thing as something new. So in your setState function you create a new array and set it equal to a map of the old prevState array with the 'completed' checkbox now changed for whichever id was clicked, then you must return the updated state of the array within the setState function. React will then run the render function again and change only any data that is different from the prevState within the DOM. 

class ToDos extends React.Component {

    constructor(props){
        super(props)
        this.state = {
            todos: todosData
        }
        this.handleCheckMark = this.handleCheckMark.bind(this)
    }

    handleCheckMark(id){
        this.setState(prevState => {
            const updatedTodos = prevState.todos.map(todo => {
                if(todo.id === id){
                    todo.completed = !todo.completed
                }
                return todo
            })
            return { todos: updatedTodos }
        })
    }

API Fetching - Using built in fetch() method
assuming the call will be made on page load, put the fetch into the componentDidMount() function, which runs as soon as the component mounts onto the rendered html, then follow these steps...

0. show the loading notice
1. fetch the source url
2. then turn the url into proper json object
3. then process the data/remove the loading notice
3Note - every time the state changes, the render() method will run again, in this case, displaying the newly updated content from the api call

.componentDidMount(){
    this.setState({ loading: true })
    .fetch(source_url)
        .then(response => response.json())
        .then(data => {
            this.setState({
                loading: false,
                character: data.name
            })
        })
}

Forms in React - setState, push current state as the value of the input. in this way the value can always be validated or processed as the user is typing and the input value will always be accurate.

See Practice To Do List in dev practice folder for example form submissions

forms should be in its own component

handleChange function should always be created. that function will update the form element with the new typed in state every time a user types something

handleSubmit function should always be created. this function will handle the submission by preventing default, sending the data to the parent component, typically passing along the data e.target.value of the form element. that function also will set the state in the form component back to blank

the function that was passed into the form component, and then called from the handleSubmit function will process the data, updating the main state, which will re-render the content.

Higher Order Components
A functional component that takes in an entire other component as a parameter and returns a new component that contains the passed in component. This is not designed React process, it simply a way to use React's built in features to get to do something different. It is mainly used by third-party libraries like Redux to add additional features to a component. See here for more details...

Component Lifecycle Methods React Docs
In a class component, React will read the constructor() function, then the componentWillMount() function, which is deprecated in React, so now it will be static getDerivedStateFromProps(), then the render() function, then the componentDidMount() function.

Say you are using Redux and you have a mapStateToProps() function. This function will run after all of the above, and because it will pass in new props that didn't exist the first time around, a new Updating lifecycle will begin.

In other words... any time props or state update, React jumps into the Updating lifecycle. 

In the Updating lifecycle, React will first look at componentWillReceiveProps() function, then the shouldComponentUpdate() function, then componentWillUpdate() function, then render() then componentDidUpdate()

BUT - that cycle has been deprecated in new React, so the new Updating lifecycle goes like this...

static getDerivedStateFromProps(), then shouldComponentUpdate(), then render(), then getSnapshotBeforeUpdate(), then componentDidUpdate()