Skip to content

Instantly share code, notes, and snippets.

@Mirakurun
Last active October 11, 2022 03:07
Show Gist options
  • Save Mirakurun/6c3cede04065b0d343ec378329454fbb to your computer and use it in GitHub Desktop.
Save Mirakurun/6c3cede04065b0d343ec378329454fbb to your computer and use it in GitHub Desktop.
React Notes

☢️ React Notes

Author: Kevin Chhay

📑 Table of Contents

  1. Installation
  2. Introduction
  3. Introducing JSX
  4. Function Component and Props
  5. Composition
  6. Handling Events
  7. State Hook
  8. Forms
  9. Lists
  10. Conditional Rendering
  11. Dynamically-Computed Styles

🛠️ Installation

https://reactjs.org/docs/getting-started.html

ℹ️ Introduction

https://reactjs.org/docs/hello-world.html

Hello World

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<h1>Hello, world!</h1>);

Introducing JSX

https://reactjs.org/docs/introducing-jsx.html

Embedding Expressions in JSX

https://reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx

const name = "Josh Perez";
const element = <h1>Hello, {name}</h1>;

Function Component and Props

https://reactjs.org/docs/components-and-props.html#function-and-class-components

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

Alternative:

const Welcome = (props) => {
  return <h1>Hello, {props.name}</h1>;
}

Export:

const Welcome = (props) => {
  return <h1>Hello, {props.name}</h1>;
}

export default Welcome;

Import:

import Welcome from "./components/Welcome";

const App = () => {
  return (
    <div>
      <Welcome />
    </div>
  );
}

Child-to-Parent Component Communication (Bottom-up)

// Child Component
const Child = (props) => {
  const clickHandler = () => {
    props.onGetMessage("Hello World");
  }

  return <button onClick={clickHandler}>Click Me</button>;
}
// Parent Component
import Child from "./components/child";

const Parent = () => {
  const getMessageHandler = (message) => {
    console.log(message);
  }

  return (
    <div>
      <Child onGetMessage={getMessageHandler} />
    </div>
  );
}

Composition

https://reactjs.org/docs/composition-vs-inheritance.html

Use the special children prop to pass children elements directly into their output:

function FancyBorder(props) {
  return (
    <div className={"FancyBorder FancyBorder-" + props.color}>
      {props.children}
    </div>
  );
}

This lets other components pass arbitrary children to them by nesting the JSX:

function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">Welcome</h1>
      <p className="Dialog-message">Thank you for visiting our spacecraft!</p>
    </FancyBorder>
  );
}

Handling Events

https://reactjs.org/docs/handling-events.html

const Component = () => {
  const clickHander = () => {
    console.log("Clicked!");
  }

  return <button onClick={clickHandler}>Click Me</button>;
}

State Hook

https://reactjs.org/docs/hooks-state.html

import React, { useState } from "react";

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

Multiple State:

import React, { useState } from "react";

const Component = () => {
  const [userInput, setUserInput] = useState({
    enteredTitle: "",
    enteredAmount: "",
    enteredDate: ""
  });

  const titleChangeHandler = (event) => {
    setUserInput((prevState) => {
      return {
        ...prevState,
        enteredTitle: event.target.value
      };
    });
  }

  return (
    // ...
  );
}

Forms

https://reactjs.org/docs/forms.html

import React, { useState } from "react";

const Component = () => {
  const [name, setName] = useState("");

  const nameChangeHandler = (event) => {
    setName(event.target.value);
  }

  const submitHandler = (event) => {
    event.preventDefault();
  }

  return (
    <form onSubmit={submitHandler}>
      <div>Name: {name}</div>
      <input type="text" value={name} onChange={nameChangeHandler} />
    </form>
  );
}

Lists

https://reactjs.org/docs/lists-and-keys.html

Embedding map() in JSX:

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );
}

Conditional Rendering

https://reactjs.org/docs/conditional-rendering.html

Logical && Operator

const Component = () => {
  return (
    <div>
      {false && "Hello World"}
      {true && "Greetings"}
    </div>
  );
}

Conditional (Ternary) Operator

const Component = () => {
  const isLoggedIn = true;
  return <div>{isLoggedIn ? "Logged in" : "Not logged in"}</div>;
}

Dynamically-Computed Styles

https://reactjs.org/docs/dom-elements.html#style

⚠️ In most cases, className should be used to reference classes defined in an external CSS stylesheet. style is most often used in React applications to add dynamically-computed styles at render time.

Inline Style

const Component = () => {
  let textColor = "alert";
  textColor = "alert" ? "red" : "green";
  return <div style={{color: textColor}}>Hello World</div>;
}

Dynamic Class

const Component = () => {
  const textColor = "alert"
  return (
    <div className={`form-control ${textColor === "alert" && "text-danger"}`}>
      Hello World
    </div>
  );
}

Fragments

https://reactjs.org/docs/fragments.html

Short Syntax

const Component = () => {
  return (
    <>
      <td>Hello</td>
      <td>World</td>
    </>
  );
}

Portals

https://reactjs.org/docs/portals.html

<!-- index.html -->
<html>
  <body>
    <div id="app-root"></div>
    <div id="modal-root"></div>
  </body>
</html>
// Component.js
import ReactDOM from "react-dom";
import Modal from "./components/modal";

const Component = () => {
  return (
    <div>
      {ReactDOM.createPortal(<Modal />, document.getElementById("modal-root"))}
    </div>
  );
}

Refs

https://reactjs.org/docs/refs-and-the-dom.html

⚠️ Using refs to access the form values from the DOM is considered an uncontrolled compoment. It is recommended to use controlled components.

import React, { useRef } from "react";

const Component = () => {
  const nameInputRef = useRef();

  const clickHandler = () => {
    console.log(nameInputRef.current.value);
  }

  return (
    <div>
      <input type="text" ref={nameInputRef} />
      <button onClick={clickHandler} />
    </div>
  );
}

Effect Hook

https://reactjs.org/docs/hooks-effect.html

⚠️ If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.

Without Dependencies (empty array)

import React, { useState, useEffect } from "react";

const Component = () => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(() => {
    if (localStorage.getItem("isLoggedIn") === "1") {
      setIsLoggedIn(true);
    }
  }, []);

  return <div>{isLoggedIn ? "Logged in" : "Not logged in"}</div>;
}

With Dependencies

import React, { useState, useEffect } from "react";

const Component = () => {
  const [emailInput, setEmailInput] = useState("");
  const [passwordInput, setPasswordInput] = useState("");
  const [isFormValid, setIsFormValid] = useState(false);

  const emailChangeHandler = (event) => {
    setEmailInput(event.target.value);
  }

  const passwordChangeHandler = (event) => {
    setPasswordInput(event.target.value);
  }

  useEffect(() => {
    // Debounce
    const id = setTimeout(() => {
      setIsFormValid(emailInput.includes("@"));
    }, 500);

    // Clean up function (runs before the effect)
    return () => {
      clearTimeout(id);
    };
  }, [emailInput]); // Only re-run the effect if emailInput changes

  return (
    <form> 
      <p>{!isFormValid && "Enter a valid email."}</p>
      <input type="text" value={emailInput} onChange={emailChangeHandler} />
      <input type="text" value={passwordInput} onChange={passwordChangeHandler} />
    </form>
  );
}

Reducer Hook

https://reactjs.org/docs/hooks-reference.html#usereducer

import React, { useReducer } from "react";

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, {count: 0});
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

Context API

https://reactjs.org/docs/context.html

// store/auth-context.js
import React from "react"

// Passing an object into createContext method is optional.  It's just for better auto-completion in the IDE.
const AuthContext = React.createContext({
  isLoggedIn: false,
  onLogout: () => {}
});

export default AuthContext;
// Parent
// App.js
import React, { useState } from "react";
import Login from "./components/Login/Login";
import Home from "./components/Home/Home";
import MainHeader from "./components/MainHeader/MainHeader";
import AuthContext from "./store/auth-context";

const App = () => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const loginHandler = () => {
    // do stuff
  };

  const logoutHandler = () => {
    // do stuff
  };

  return (
    <AuthContext.Provider
      value={{
        isLoggedIn: isLoggedIn,
        onLogout: logoutHandler
      }}
    >
      <MainHeader />
      <main>
        {!isLoggedIn && <Login onLogin={loginHandler} />}
        {isLoggedIn && <Home onLogout={logoutHandler} />}
      </main>
    </AuthContext.Provider>
  );
}

export default App;
// Child
// components/MainHeader.js
import React from 'react';
import Navigation from './Navigation';

const MainHeader = () => {
  return (
    <header className={classes['main-header']}>
      <h1>A Typical Page</h1>
      <Navigation />
    </header>
  );
};

export default MainHeader;
// Grandchild
// components/Navigation.js
import React, { useContext } from "react";
import AuthContext from "../../store/auth-context";

const Navigation = () => {
  const ctx = useContext(AuthContext);

  return (
    <nav>
      <ul>
        {ctx.isLoggedIn && (
          <li>
            <a href="/">Users</a>
          </li>
        )}
        {ctx.isLoggedIn && (
          <li>
            <a href="/">Admin</a>
          </li>
        )}
        {ctx.isLoggedIn && (
          <li>
            <button onClick={ctx.onLogout}>Logout</button>
          </li>
        )}
      </ul>
    </nav>
  );
}

export default Navigation;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment