Skip to content

mangoomeh/learn-react

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 

Repository files navigation

React

Table of contents

  1. About
  2. Props
  3. State
  4. UseRef
  5. UseEffect
  6. ConditionalRendering
  7. CreatePortal
  8. HTTP-Requests
  9. UseContext
  10. Reducer
  11. ReactRouter
  12. Redux
  13. Testing

About

React is a Javascript Library used to craft modern day UI.

Top Sites using React

  • Airbnb
  • Cloudflare
  • Dropbox
  • Facebook
  • Instagram

Notes about React

  1. React App gets sent over from server
  2. Everything is downloaded unlike html where everything is downloaded when needed
  3. React has many ways to do a thing in constrast to Angular
  4. Other famous frameworks: Angular, Vue

How to create React app:

npx create-react-app name-of-app

How to install with package.json:

npm install

JSX - JavaScript XML

  • className="myClass"
  • Only one parent can be returned in JSX component
  • Html cannot read javascript objects
  • Wrap javascript in curly braces. E.g. {variableName}

Functional component

  • Each js file should only hold one functional component
  • Component naming convention: CamelCase

Props

  • Props are properties that can be passed down to a child component from a parent component
  • Props is a javascript object
  • Each prop is a key-value pair
  • Props passing is unidirectional (Parent -> Child)
  • Example usage:

    Parent:
    const Parent = () => {
      return ( <Child title="hello" /> )
    }
    
    Child:
    const Child = (props) => {
      return ( <div>{props.title}</div> )
    }
    

State

How to import

import { useState } from "react"

How to use

Using array destructuring:
const [state, setState] = useState(initialValue);

About

  • Component rerenders when the function setState is called
  • Rerendering happens only after changing of state
  • Console.log does not log the correct values of state

Controlled Form for Inputs

const [state, setState] = useState(initialValue);
const handleInput = (event) => {
  setState(event.target.value);
}

return (
<input value={state} onChange={handleInput} />
)

Ref

How to import

import { useRef } from "react"

About

  • Does not rerender when executed, might rerender

Uncontrolled Form

const reference = useRef(initialValue);
<input ref={reference} />
const focus = () => {reference.current.focus()} // this changes focus to the input element

Component Lifecycle

Class Components

  • componentDidMount()
  • componentDidUpdate()
  • componentWillUnmount()

Functional Components Equivalent

  • useEffect(() => {}, [])
  • useEffect(() => {})
  • useEffect(() => { return () => {} })

Conditional Rendering

Usage

  • Shortcircuiting of logic:
{!{isLoading} && {displayComponent}}
  • Ternary Operator:
{isLoading ? <LoadingSpinner /> : {displayComponent}}

About conditionals

  • Logical AND (&&) return false when it hits a false-y value and return last value if all earlier values are truth-y
  • Logical OR (||) continues evaluating when it hits a false-y value until it hits a truth-y value

Create Portal

How to import

import ReactDOM from "react-dom"

About

  • create portal takes in JSX component followed by where to put it

Usage

Error modal:

const OverLay = () => {}
const mainFunctionName => {
  return (
    <>
      {ReactDOM.createPortal(
        <Overlay />, document.querySelector("#modal-root")
      )}
    </>
  )
}

HTTP Requests

Javascript ES6 Fetch API

try {
      const res = await fetch(url);
      if (res.status !== 200) {
        throw new Error("Something went wrong.") // throw will go to catch
      }
      const data = await res.json();
      console.log(data);
    } catch (err) {
      setError(err.message);
    }

Abort Controller

useEffect(() => {
  const url = "https://jsonplaceholder.typicode.com/posts/" + selection;
  const controller = new AbortController();
  fetchPost(url, controller.signal);

  return () => {
    controller.abort();
  };
}, [selection]);

Context

About

  • useContext is used to pass props easily as opposed to the usual props drilling
  • Danger of useContext is that everything within the context provider gets rerendered when states changes

How to use

  1. Create a context file:
import { createContext } from "react";
const MyContext = createContext();
export default MyContext;
  1. Import context and wrap the components:
import MyContext from "./MyContext";

const MyComponent = () => {
  const var1 = "1234"
  const var2 = "abcd"
  return (
    <MyContext.Provider value={var1, var2}>
      <ChildComponent />
    </MyContext.Provider>
  )
}
  1. Access values in child component:
import MyContext from "./MyContext";
import { useContext } from "react";
const ChildComponent = () => {
  const myContext = useContext(MyContext);
  return (
    <>
      <div>{myContext.var1}</div>
      <div>{myContext.var2}</div>
    </>
  )
}

Reducer

About

Similar to useState, reducer is used to deal with more complex state structures such as array and javascript objects or complex logic

Reducer Function with UseState Hook

import { useState } from "react";
const [state, setState] = useState(initialValue);

const reducer = (state, action) => {
  switch (action) {
    case "increase":
      return state + 1;
      break;
    case "decrease":
      return state - 1;
      break;
    case "reset":
      return 0
      break;
    default:
      return state;
  }
}

<button onClick={setState(reducer(state, "increase"))}>Increase</button>
<button onClick={setState(reducer(state, "decrease"))}>Decrease</button>
<button onClick={setState(reducer(state, "reset"))}>Reset</button>

UseReducer Hook

import { useReducer } from "react";
const [state, dispatch] = useReducer(reducer, initialValue);

const reducer = (state, action) => {
  switch (action.type) {
    case "increase":
      return state + action.value;
      break;
    case "decrease":
      return state - action.value;
      break;
    case "reset":
      return action.value
      break;
    default:
      return state;
  }
}

return (
  <button onClick={dispatch({type: "increase", value: 1})}>Increase</button>
  <button onClick={dispatch({type: "decrease", value: 1})}>Decrease</button>
  <button onClick={dispatch({type: "reset", value: 0})}>Reset</button>
);

React Router

React Router 5

  1. Install router:
npm i react-router-dom@5
  1. Set up router in index.js:
import ReactDOM from "react-dom";

import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);
  1. Set up routes in your component:
  • import Route
  • import Pages
  • set route paths to wrap each page
import React from "react";
import { Route, Redirect, Switch } from "react-router-dom";
import NavBar from "./components/NavBar";
import Details from "./pages/Details";
import Main from "./pages/Main";
import PageOne from "./pages/PageOne";
import PageThree from "./pages/PageThree";
import PageTwo from "./pages/PageTwo";

function App() {
  return (
    <div className="container">
      <NavBar />
      <Switch>
        <Route exact path="/">
          <Redirect to="/page-one" />
        </Route>
        <Route exact path="/page-one">
          <PageOne></PageOne>
        </Route>
        <Route path="/page-two">
          <PageTwo></PageTwo>
        </Route>
        <Route path="/page-one/:item">
          <Details />
        </Route>
        <Route path="/page-three">
          <PageThree></PageThree>
        </Route>
      </Switch>
    </div>
  );
}

export default App;
  1. Use links to link to your pages
import { Link } from "react-router-dom";

<Link to="/">Main</Link>
<Link to="/page-one">Page One</Link>
<Link to="/page-two">Page Two</Link>
<Link to="/page-three">Page Three</Link>

Some notes

  • React router dom 5 use greedy search for path so it will always display the main page
  • To fix the issue where only main page is shown is to use exact keyword as seen in "3. Set up routes"
  • Using switch ensures that only one page is displayed at a time, however does not eliminate the greedy search for path problem:
import { Switch } from "react-router-dom";

<Switch>
  <Route exact path="/">
    <Main />
  </Route>
  <Route path="/page-one">
    <PageOne />
  </Route>
</Switch>

React Router 6

  • Install latest react router:
npm i react-router-dom
  • Example:
const App = () => {
  return (
    <div className="container">
      <NavBar />
      <Routes>
        <Route path="/" element={<Navigate replace to="/page-one" />} />
        <Route path="/page-one" element={<PageOne />} />
        <Route path="/page-two" element={<PageTwo />} />
        <Route path="/page-one/:item" element={<Details />} />
        <Route path="/page-three" element={<PageThree />} />
      </Routes>
    </div>
  );
}

export default App;

  • Use NavLinks to link to pages:
import { NavLink } from "react-router-dom";

<NavLink to="/">Main</NavLink>
<NavLink to="/page-one">Page One</NavLink>
<NavLink to="/page-two">Page Two</NavLink>
<NavLink to="/page-three">Page Three</NavLink>

Notes about React Router 6

  • Pretty new, might not be implemented in many companies
  • No need for Switch
  • No need for exact keyword
  • Wrap all route in <Routes>
  • NavLink instead of Link
  • Navigate instead of redirect

Redux

Redux Toolkit

  1. Install Redux Toolkit
npm install @reduxjs/toolkit
  1. Create Slice Reducers and Actions AKA createSlice
  • import createSlice
  • "mutating" logic can be used in createSlice
  • choose to create "selector" functions
import { createSlice } from "@reduxjs/toolkit";

const counterSlice = createSlice({
  name: "counter",
  initialState: {
    value: 0
  },
  reducers: {
    increment: state => {
      state.value += 1
    },
    decrement: state => {
      state.value -= 1
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload
    }
  }
})

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
  1. Create Redux Store AKA configureStore
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice"

const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

export default store;
  1. Create Component
  • Read data with useSelector
  • Change store state using useDispatch
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { decrement, increment, incrementByAmount } from "./counterSlice";

const myComponent = () => {
  const dispatch = useDispatch();
  const count = useSelector((state) => state.value);

  return (
    <>
      <div>Current value: {count}</div>
      <button onClick={() => dispatch(increment())}>+</>
      <button onClick={() => dispatch(decrement())}>-</>
    </>
  )
}
  1. Provide the Store
import ReactDOM from "react-dom"
import React from "react"
import { Provider } from "react-redux"

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published