Basic

npm create vite@latest my-first-react-app -- --template react
function Greeting() {
  return <h1>"I swear by my pretty floral bonnet, I will end you."</h1>;
}
 
export default Greeting;

JSX

create element funtion in react (for creating a element without jsx) https://react.dev/reference/react/createElement

const element = createElement(type, props, ...children)
 
  1. camelCase Most things.

    JSX turns into JavaScript, and attributes of elements become keys of JavaScript objects, so you can’t use dashes or reserved words such as class. Because of this, many HTML attributes are written in camelCase. Instead of stroke-width, you’d use strokeWidth, and instead of class you’d use className.

    Correct:

    function App() {
      return (
        <>
          <div className="container">
            <svg>
              <circle cx="25" cy="75" r="20" stroke="green" strokeWidth="2" />
            </svg>
          </div>
        </>
      );
    }

    Incorrect:

    function App() {
      return (
        <>
          <div class="container">
            <svg>
              <circle cx="25" cy="75" r="20" stroke="green" stroke-width="2" />
            </svg>
          </div>
        </>
      );
    }

When you want to pass a string attribute to JSX, you put it in single or double quotes:

But what if you want to dynamically specify the src or alt text? You could use a value from JavaScript by replacing " and " with { and }:

  const avatar = 'https://i.imgur.com/7vQD0fPs.jpg';
  const description = 'Gregorio Y. Zara';
  return (
    <img
      className="avatar"
      src={avatar}
      alt={description}
    />
  );
}
 
 

Any JavaScript expression will work between curly braces, including function calls like formatDate():

const today = new Date();
 
function formatDate(date) {
  return new Intl.DateTimeFormat(
    'en-US',
    { weekday: 'long' }
  ).format(date);
}
 
export default function TodoList() {
  return (
    <h1>To Do List for {formatDate(today)}</h1>
  );
}
 
 

Where to use curly braces 

You can only use curly braces in two ways inside JSX:

  1. As text directly inside a JSX tag: <h1>{name}'s To Do List</h1> works, but <{tag}>Gregorio Y. Zara's To Do List</{tag}> will not.
  2. As attributes immediately following the = sign: src={avatar} will read the avatar variable, but src="{avatar}" will pass the string "{avatar}".

In addition to strings, numbers, and other JavaScript expressions, you can even pass objects in JSX. Objects are also denoted with curly braces, like { name: "Hedy Lamarr", inventions: 5 }. Therefore, to pass a JS object in JSX, you must wrap the object in another pair of curly braces: person={{ name: "Hedy Lamarr", inventions: 5 }}.

export default function TodoList() {
  return (
    <ul style={{
      backgroundColor: 'black',
      color: 'pink'
    }}>
      <li>Improve the videophone</li>
      <li>Prepare aeronautics lectures</li>
      <li>Work on the alcohol-fuelled engine</li>
    </ul>
  );
}
 
 
 
 

rendering techniques

rendering a list

function App() {
  const animals = ["Lion", "Cow", "Snake", "Lizard"];
  return (
    <div>
      <h1>Animals: </h1>
      <ul>
        {animals.map((animal) => {
          return <li key={animal}>{animal}</li>;
        })}
      </ul>
    </div>
  );
}
function App() {
  const animals = ["Lion", "Cow", "Snake", "Lizard"];
  const animalsList = animals.map((animal) => <li key={animal}>{animal}</li>)
  
  return (
    <div>
      <h1>Animals: </h1>
      <ul>
        {animalsList}
      </ul>
    </div>
  );
}
function ListItem(props) {
  return <li>{props.animal}</li>
}
 
function List(props) {
  return (
    <ul>
      {props.animals.map((animal) => {
        return <ListItem key={animal} animal={animal} />;
      })}
    </ul>
  );
}
 
function App() {
  const animals = ["Lion", "Cow", "Snake", "Lizard"];
 
  return (
    <div>
      <h1>Animals: </h1>
      <List animals={animals} />
    </div>
  );
}

Conditional rendering

ternary operator

function List(props) {
  return (
    <ul>
      {props.animals.map((animal) => {
        return animal.startsWith("L") ? <li key={animal}>{animal}</li> : null;
      })}
    </ul>
  );
}
 
function App() {
  const animals = ["Lion", "Cow", "Snake", "Lizard"];
 
  return (
    <div>
      <h1>Animals: </h1>
      <List animals={animals} />
    </div>
  );
}

Using && operator ??

function List(props) {
  return (
    <ul>
      {props.animals.map((animal) => {
        return animal.startsWith("L") && <li key={animal}>{animal}</li>;
      })}
    </ul>
  );
}
 
function App() {
  const animals = ["Lion", "Cow", "Snake", "Lizard"];
 
  return (
    <div>
      <h1>Animals: </h1>
      <List animals={animals} />
    </div>
  );
}

Falsy values in JSX, a common pitfall

In JSX, values like nullundefined, and false do not render anything, and you might ask aren’t they falsy values? So you might think a value like 0 or an empty string does the same thing. It is a common pitfall. They are valid in JSX and will be rendered completely fine, so be sure to be aware of that!

Other ways of conditional rendering (if,else,switch)

function List(props) {
  if (!props.animals) {
    return <div>Loading...</div>;
  }
 
  if (props.animals.length === 0) {
    return <div>There are no animals in the list!</div>;
  }
 
  return (
    <ul>
      {props.animals.map((animal) => {
        return <li key={animal}>{animal}</li>;
      })}
    </ul>
  );
}
 
function App() {
  const animals = [];
 
  return (
    <div>
      <h1>Animals: </h1>
      <List animals={animals} />
    </div>
  );
}

this could be done with other operator like ternary and &&

function List(props) {
  return (
    <>
      {!props.animals ? (
        <div>Loading...</div>
      ) : props.animals.length > 0 ? (
        <ul>
          {props.animals.map((animal) => {
            return <li key={animal}>{animal}</li>;
          })}
        </ul>
      ) : (
        <div>There are no animals on the list!</div>
      )}
    </>
  );
}
 
// or
function List(props) {
  return (
    <>
      {!props.animals && <div>Loading...</div>}
      {props.animals && props.animals.length > 0 && (
        <ul>
          {props.animals.map((animal) => {
            return <li key={animal}>{animal}</li>;
          })}
        </ul>
      )}
      {props.animals && props.animals.length === 0 && <div>There are no animals in the list!</div>}
    </>
  );
}
 
function App() {
  const animals = [];
 
  return (
    <div>
      <h1>Animals: </h1>
      <List animals={animals} />
    </div>
  );
}

JSX elements directly inside a map() call always need keys!

Keys

const todos = [
  { task: "mow the yard", id: uuid() }, 
  { task: "Work on Odin Projects", id: uuid() },
  { task: "feed the cat", id: uuid() },
];
 
function TodoList() {
  return (
    <ul>
      {todos.map((todo) => (
        // here we are using the already generated id as the key.
        <li key={todo.id}>{todo.task}</li>
      ))}
    </ul>
  ) 
}
     // DON'T do the following i.e. generating keys during render    
          <li key={uuid()}>{todo.task}</li>

Props

props basic

function Button(props) {
 
  const buttonStyle = {
    color: props.color,
    fontSize: props.fontSize + 'px'
  };
 
  return (
    <button style={buttonStyle}>{props.text}</button>
  )
}
 
export default function App() {
  return (
    <div>
      <Button text="Click Me!" color="blue" fontSize={12} />
      <Button text="Don't Click Me!" color="red" fontSize={12} />
      <Button text="Click Me!" color="blue" fontSize={20} />
    </div>
  );
}

props destructuring

function Button({ text, color, fontSize }) {
  const buttonStyle = {
    color: color,
    fontSize: fontSize + "px"
  };
 
  return <button style={buttonStyle}>{text}</button>;
}
 
export default function App() {
  return (
    <div>
      <Button text="Click Me!" color="blue" fontSize={12} />
      <Button text="Don't Click Me!" color="red" fontSize={12} />
      <Button text="Click Me!" color="blue" fontSize={20} />
    </div>
  );
}

default props 2 ways

function Button({ text, color, fontSize }) {
  const buttonStyle = {
    color: color,
    fontSize: fontSize + "px"
  };
 
  return <button style={buttonStyle}>{text}</button>;
}
 
Button.defaultProps = {
  text: "Click Me!",
  color: "blue",
  fontSize: 12
};
 
export default function App() {
  return (
    <div>
      <Button />
      <Button text="Don't Click Me!" color="red" />
      <Button fontSize={20} />
    </div>
  );
}
function Button({ text = "Click Me!", color = "blue", fontSize = 12 }) {
  const buttonStyle = {
    color: color,
    fontSize: fontSize + "px"
  };
 
  return <button style={buttonStyle}>{text}</button>;
}

function in prop

function Button({ text = "Click Me!", color = "blue", fontSize = 12, handleClick }) {
  const buttonStyle = {
    color: color,
    fontSize: fontSize + "px"
  };
 
  return (
    <button onClick={() => handleClick('https://www.theodinproject.com')} style={buttonStyle}>
      {text}
    </button>
  );
}
 
export default function App() {
  const handleButtonClick = (url) => {
    window.location.href = url;
  };
 
  return (
    <div>
      <Button handleClick={handleButtonClick} />
    </div>
  );
}

When supplying a parameter to the function we can’t just write onClick={handleClick('www.theodinproject.com')}, and instead must attach a reference to an anonymous function which then calls the function with the parameter. Like the previous example, this is to prevent the function being called during the render.

There are also other ways to implement this behavior. Hint: curried functions!

It is common to nest built-in browser tags:

<div>  <img /></div>

Sometimes you’ll want to nest your own components the same way:

<Card>  <Avatar /></Card>

When you nest content inside a JSX tag, the parent component will receive that content in a prop called children. For example, the Card component below will receive a children prop set to <Avatar /> and render it in a wrapper div:

import Avatar from './Avatar.js';
 
function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}
 
export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{ 
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}
 

State

import { useState } from 'react';
import { sculptureList } from './data.js';
 
export default function Gallery() {
  const [index, setIndex] = useState(0);
 
  function handleClick() {
    setIndex(index + 1);
  }
 
  let sculpture = sculptureList[index];
  return (
    <>
      <button onClick={handleClick}>
        Next
      </button>
      <h2>
        <i>{sculpture.name} </i> 
        by {sculpture.artist}
      </h2>
      <h3>  
        ({index + 1} of {sculptureList.length})
      </h3>
      <img 
        src={sculpture.url} 
        alt={sculpture.alt}
      />
      <p>
        {sculpture.description}
      </p>
    </>
  );
}
 
 

Hooks—functions starting with use—can only be called at the top level of your components or your own Hooks. You can’t call Hooks inside conditions, loops, or other nested functions. Hooks are functions, but it’s helpful to think of them as unconditional declarations about your component’s needs. You “use” React features at the top of your component similar to how you “import” modules at the top of your file.

State updater functions

A trick question. Let’s look another implementation of handleIncreaseAge; what do you think it does?

const handleIncreaseAge = () => {
   setPerson({ ...person, age: person.age + 1 });
   setPerson({ ...person, age: person.age + 1 });
}

Surely, it increase the age by 2? Nope. The above code is saying to React:

Hey, replace the current render’s person with an increase in age by 1. Then, replace the current render’s person with an increase in age by 1.

Notice the word “replace”. When you pass in the value to the setState function, React will replace the current state with the value you passed in. You might be wondering, what if I want to update the state multiple times using the latest state? This is where the state updater function comes in.

const handleIncreaseAge = () => {
   setPerson((prevPerson) => ({ ...prevPerson, age: prevPerson.age + 1 }));
   setPerson((prevPerson) => ({ ...prevPerson, age: prevPerson.age + 1 }));
}

React batches state updates

There are two setPerson calls in the above example, and from what we’ve learned so far, a setState call triggers a component re-render. So, the component should re-render twice, right? You would say yes, but React is smart. Wherever possible React batches the state updates. Here the component only re-renders once. We’d encourage you to use console.logs to verify this.

//state as a snapshot

lifting state up

Effects

when things render in useEffect

useEffect(() => {
  // This runs after every render
});
 
useEffect(() => {
  // This runs only on mount (when the component appears)
}, []);
 
useEffect(() => {
  // This runs on mount *and also* if either a or b have changed since the last render
}, [a, b]);
useEffect(
  () => {
    // execute side effect
    return () => {
      // cleanup function on unmounting or re-running effect
    }
  },
  // optional dependency array
  [/* 0 or more entries */]
)

if dependency array is empty then effect do not run on rerender if it is not present then then effect run on every rerender if dependencies then on dependencies change

There is an interesting behaviour with this hook when we use non-primitive JavaScript data types as dependencies (e.g., arrays, objects, functions). With primitive values, such as numbers and strings, we can define a variable from another variable, and they will be the same:

const a = 1
const b = 1
a === b
// Output: true

But with non-primitive values, such as objects, this behaviour is not the same:

{} === {}
// Output: false

So we need to be very careful when using objects as dependencies, because even though they may look like unaltered data, they may not be so. Instead of using objects, we may want to use their properties as dependencies:

useEffect(() => {
        // Some code that uses the properties
    }, [myObject.property1, myObject.property2]);