Christian.

React & Javascript Notes

March 19, 2021

Thank you to Anthony Sistilli for his amazing React playlist on YouTube. I’ve gone through a lot of React posts & videos to help me learn it and this is by far the resource that made it all stick. I really appreciate his approach to teach and the clarity of this examples. I know it sounds cheesy but these videos truly were the “lightbulb turning on moment” for me.

Props


Our App component is the parent to Employee and we have several ways to pass our props from parent to child. First, we’ll just pass props in our arrow function and explicitly name each prop like props.first, props.job etc.

import Employee from "./components/Employee"
function App() {
  return (
    <div>
      <Employee first={"Christian"} last={"Turner"} job={"SWE"} />
      <Employee first={"Alexa"} last={"Smith"} job={"ML Ops"} />
      <Employee first={"Brandon"} last={"Flowers"} job={"CTO"} />
      <Employee first={"Stephanie"} last={"Johnson"} job={"Manager"} />
    </div>
  )
}
const Employee = props => {
  return (
    <div>
      <h1>
        {" "}
        Name: {props.first} {props.last}{" "}
      </h1>
      <h2> Job: {props.job} </h2>
    </div>
  )
}

screenshot1

Destructuring Props

Or we can use an ES6 method called “Destructuring” to assign all our prop types to our props variable and therefore be able to drop the props.____ everywhere in our JSX. This is done on one line and makes our code a lot more readable.

const Employee = props => {
  const { firstname, lastname, age, job } = props
  return (
    <div>
      <h1>
        {" "}
        Name: {firstname} {lastname}{" "}
      </h1>
      <h2> Job: {job} </h2>
    </div>
  )
}

Destructuring Props with Named Parameters (Aliasing)

Another quick not, we can use another ES6 method called “Named Parameters” to assign alias’s to any/all props by adding a colon after it and then the alias we want to use. We’ll then pass the alias down below in the JSX. This is useful, for instance, if we’re passing in a of nested props and we have two id props or name props. As in, say we have a department name and and employee name parameter, now this is a bad naming convention, but I’m just trying to explain why aliasing could come in handy. We can alias them as {name: deptName, name: employeeName} for instance.

const Employee = props => {
  const { firstname: first, lastname: last, job: myJob } = props
  return (
    <div>
      <h1>
        {" "}
        Name: {first} {last}{" "}
      </h1>
      <h2> Job: {myJob} </h2>
    </div>
  )
}

useState


This is the first React hook we’re going over. You’ll see inside our component we immediately have array destructuring. This is common practice with hooks. We have two variable set our initial state. The first variable is going to be our state variable and the second is the updapter function. It’s common practice to name the updater function a use + first state variable name to be explicit with what’s going on. For instance: [count, setCount], [age, setAge], [name, setName] etc etc. Then, on the right side, we have our actual useState() function. Within the parentheses we put in our **initial state**. So for setCount in our Counter component, it’d be wise to set it to 0 at the start. However, if we were using an input form, we’d pass in an empty string like this useState(''). We need the field to be empty in preparation for the user to add in what they want to.

const [count, setCount] = useState(0)
const [name, setName] = useState("")

useState & updating State

In the buttons, you’ll see we have an empty arrow function that calls setCount and mutates state.

export default function Counter() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <h3>The count is: {count}</h3>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(count - 1)}>Decrement</button>
    </div>
  )
}

useState & Conditinal Rendering

Here’s another exmample of useState in action. In our App component we have a button to toggle the state of our Counter component when we click it. So we setShowCounter to false initially and then you see when we click that button we have an arrow function to set the state of our showCounter state variable to whatever it is not (i.e. if it’s false set to true, if true set to false). We do this with the bang operator. To be clear, the button’s onClick only changes the **state**, but it is our job to make sure it’s reflected in our UI. So that’s what we’re doing in this line {showCounter && <Counter />}. This is called conditional rendering. You can see it agin in the button text that changes from “show” to “hide” depending on state using the ternary operator. Another form of conditional rendering. The difference is that the ternary operator specifies what it should be in a true and false scenario. Whereas the “logical and” operator (&&) is basically saying that “if the left side of the && is true, show the right side”. So we’re not interested in showing anything if false, like we needed to in the button’s text. We are only interested in showing the content when true. Two approaches to conditional rendering.

function App() {
  const [showCounter, setShowCounter] = useState(false)
  return (
    <div>
      <button onClick={() => setShowCounter(!showCounter)}>
        {showCounter ? "Show Counter" : "Hide Counter"}
      </button>
      {showCounter && <Counter />}
    </div>
  )
}

useEffect


This hook comprises/replaces 3 old lifecyele methods: componentDidMount, componentDidUpdate, componentWillUnmount. This is a very important hook and it’s responsible for all of our updating & side effects. This hook take two parameters, a function and array. The function by default is an empty arrow function.

useEffect(
  () => {
    // effect
    return () => {
      // cleanup
    }
  } /*[input]*/
)
#CodecDMcDUcWUNotes
1useEffect(() => {});XNo array will run on everything, equivalent to passing everything into array
2useEffect(() => {}, []);Runs on mount, not on update
3useEffect(() => {}, [state]);Runs every time said state changes
4useEffect(() => { return () => {}}, []);Will run on unmount, not run on update because array is empty
5useEffect(() => { return () => {}}, [state]);Will run mount, specific state update, and on

1: useEffect(() => {});

In this example, we have the empty arrow function but no optional array passed in as the second arguement. Since we didn’t pass the array as the optional second arguement, it will be treated as if we passed everything into it. Therefore it will run on mount and on every update for everything. This is not best practice because we can have other state or things like Redux affected by this.

// will run on everything
useEffect(() => {
  console.log("The use effect ran")
})

2: useEffect(() => {}, []);

Here we’ve added in the empty array. Here we add a state variable, but that’s optional. You can think of this as the componentDidMount lifecycle hook. It will run on mount, but not ever again. We didn’t specify a state variable to tie it to so it won’t re-render on any state changes.

// componentDidMount
useEffect(() => {
  console.log("The use effect ran")
}, [])

3: useEffect(() => {}, [state]);

Now, we’ve added a variable to our state. This will now run on mount and on every update. Think of it as a componentDidMount & componentDidUpdate. It will only recall this function when the state variable we passed it is changed specifically. You can add multiple variables in this array. Again, to be clear, if we were to have a second variable, but we don’t pass it into the array, it won’t run useEffect when it’s changed. It must be passed.

// componentDidUpdate
useEffect(() => {
  console.log("The use effect ran")
}, [count])

4: useEffect(() => { return () => {}}, []);

By adding a return function, it will now work like a componentWillMount. So, in this example, it will run on mount, as always, it will not run on update since no state variable was passed to it, and now it will run on the component’s unmount.

// componentWillUnmount
useEffect(() => {
  console.log("The use effect ran")
  return () => {
    console.log("the return is being ran")
  }
}, [])

5: useEffect(() => { return () => {}}, [state]);

Lastly, we’ve added both a return statement and a state variable in our useEffect function. Now, it’s not going to run as a typical componentWillUnmount. It will run as a componentWillUnmount specifically when an item in the array changes. For instance, when our count changes, the second console.log() runs first, printing our current count before change, then it will update, and THEN the first console.log() runs with the new updated count. Lastly, once we unmount our component, that second console.log() will run one final time.

// componentWillUnmount
useEffect(() => {
  console.log(`The count has updated to ${count}`)
  return () => {
    console.log(`we are in the cleanup - the count is ${count}`)
  }
}, [count])

Written by Christian Turner
Follow me on Twitter