ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • The State Hook
    React 2021. 12. 6. 01:27

    이 글은 React의 State Hook에 관한 개념을 정리하기 위해 작성하였습니다.



    < Why Use Hooks? >

    With Hooks, we can use simple function components to do lots of the fancy things that we could only do with class components in the past.

    Hooks don’t work inside classes — they let us use fancy React features without classes.

     

    < Why we use Hooks? >
    In Class components, They :
    1. are difficult to reuse between components
    2. are tricky and time-consuming to test
    3. have confused many developers and caused lots of bugs

    -> The React core team heard all of this feedback from developers like us, and they engineered an incredible solution for us! React 16.8+ supports Hooks.

     

    • React offers a number of built-in Hooks. A few of these include useState(), useEffect(), useContext(), useReducer(), and useRef(). See the full list in the docs.

     

     


    < Update Function Component State >

    To set and update function component state, use State Hook useState( ) method.

     

    • The State Hook is a named export from the React library, so we import it like this :
      import React, { useState } from 'react';​
    • useState( ) is a JavaScript function defined in the React library. When we call this function, it returns an array with two values :
      1. current state - the current value of this state
      2. state setter - a function that we can use to update the value of this state
      const [currentState, setCurrentState] = useState(firstState);
      -> Calling the state setter signals to React that the component needs to re-render, so the whole function defining the component is called again.

     

    Example)

    import React, { useState } from "react";
     
    function Toggle() {
      const [toggle, setToggle] = useState();
     
      return (
        <div>
          <p>The toggle is {toggle}</p>
          <button onClick={() => setToggle("On")}>On</button>
          <button onClick={() => setToggle("Off")}>Off</button>
        </div>
      );
    }

     

     


    < Initialize State >

    To initialize our state with any value we want, simply pass the initial value as an argument to the useState( ) function call.

     

    • If we don’t pass an initial value when calling useState(), then the current value will be undefined.
    • If we don’t have the value needed during the first render, we can explicitly pass null instead of just leaving the value as undefined.

     

    Example)

    const [isLoading, setIsLoading] = useState(true);

    : first state value is true

     

     


    < Use State Setter Outside of JSX >

    This is a common pattern of using setState( )

    It’s a good idea to separate that logic from everything else going on in our JSX.

     

    Example)

    import React, { useState } from 'react';
     
    export default function EmailTextInput() {
      const [email, setEmail] = useState('');
      const handleChange = (event) => {
        const updatedEmail = event.target.value;
        setEmail(updatedEmail);
      }
     
      return (
        <input value={email} onChange={handleChange} />
      );
    }

    : The event handler is defined inside of the definition for our function component, but outside of our JSX.

     

     


    < Set From Previous State >

    Often, the next value of our state is calculated using the current state.
    In this case, it is best practice to update state with a callback function.

     

    • When our state setter calls the callback function, the callback function takes our previous state as an argument.

     

    Example)

    import React, { useState } from 'react';
     
    export default function Counter() {
      const [count, setCount] = useState(0);
     
      const increment = () => setCount(prevCount => prevCount + 1);
     
      return (
        <div>
          <p>Wow, you've clicked that button: {count} times</p>
          <button onClick={increment}>Click here!</button>
        </div>
      );
    }

    : 'prevCount' is our previous state

     

     


    < Arrays in State >

    JavaScript arrays are the best data model for managing and rendering JSX lists.

     

    Example)

    import React, { useState } from "react";
     
    const options = ["Bell Pepper", "Sausage", "Pepperoni", "Pineapple"];
     
    export default function PersonalPizza() {
      const [selected, setSelected] = useState([]);
     
      const toggleTopping = ({target}) => {
        const clickedTopping = target.value;
        setSelected((prev) => {
         // check if clicked topping is already selected
          if (prev.includes(clickedTopping)) {
            // filter the clicked topping out of state
            return prev.filter(t => t !== clickedTopping);
          } else {
            // add the clicked topping to our state
            return [clickedTopping, ...prev];
          }
        });
      };
     
      return (
        <div>
          {options.map(option => (
            <button value={option} onClick={toggleTopping} key={option}>
              {selected.includes(option) ? "Remove " : "Add "}
              {option}
            </button>
          ))}
          <p>Order a {selected.join(", ")} pizza</p>
        </div>
      );
    }

    In this example, we are using two arrays :

    • options is an array that contains the names of all of the pizza toppings available
    • selected is an array representing the selected toppings for our personal pizza

    +. We like to define static data models outside of our function components since they don’t need to be recreated each time our component re-renders : 'options' array

     

     


    < Objects in State >

    When we work with a set of related variables, it can be very helpful to group them in an object.

     

    Example)

    export default function Login() {
      const [formState, setFormState] = useState({});
     
      const handleChange = ({ target }) => {
        const { name, value } = target;
        setFormState((prev) => ({
          ...prev,
          [name]: value
        }));
      };
     
      return (
        <form>
          <input
            value={formState.firstName}
            onChange={handleChange}
            name="firstName"
            type="text"
          />
          <input
            value={formState.password}
            onChange={handleChange}
            type="password"
            name="password"
          />
        </form>
      );
    }

    : Did you notice [name]? This Computed Property Name allows us to use the name variable as a property key!

     

     


    < Separate Hooks for Separate States >

    While there are times when it can be helpful to store related data in a data collection like an array or object, it can also be helpful to separate data that changes separately into completely different state variables. 

    Managing dynamic data with separate state variables has many advantages, like making our code more simple to write, read, test, and reuse across components.

     

    For example : State for a subject you are studying at school

    function Subject() {
      const [state, setState] = useState({
        currentGrade: 'B',
        classmates: ['Hasan', 'Sam', 'Emma'],
        classDetails: {topic: 'Math', teacher: 'Ms. Barry', room: 201};
        exams: [{unit: 1, score: 91}, {unit: 2, score: 88}]);
      });

    : This would work, but how messy it could get to copy over all the other values when we need to update something in this big state object.

    setState((prev) => ({
     ...prev,
      exams: prev.exams.map((exam) => {
        if( exam.unit === updatedExam.unit ){
          return { 
            ...exam,
            score: updatedExam.score
          };
        } else {
          return exam;
        }
      }),
    }));

    : Complex code like this is likely to cause bugs!

     

    So, Separate States!

    function Subject() {
      const [currentGrade, setGrade] = useState('B');
      const [classmates, setClassmates] = useState(['Hasan', 'Sam', 'Emma']);
      const [classDetails, setClassDetails] = useState({topic: 'Math', teacher: 'Ms. Barry', room: 201});
      const [exams, setExams] = useState([{unit: 1, score: 91}, {unit: 2, score: 88}]);
      // ...
    }

     

     

     

     

     

    'React' 카테고리의 다른 글

    Style  (0) 2021.12.06
    The Effect Hook  (0) 2021.12.06
    Function Components  (0) 2021.12.05
    Component Lifecycle  (0) 2021.12.02
    React Pattern  (0) 2021.11.30

    댓글

Designed by Tistory.