너무 많은 일을 하는 React 구성 요소(및 이를 단순화하는 방법)

26249 단어 reactwebdevcleancode
일부 구성 요소가 너무 많은 작업을 수행하고 있다고 생각하십니까?

렌더링 조건을 지정하는 플래그 역할을 하는 새로운 부울 소품을 추가했던 때를 기억하십니까? 이런 일이 많이 발생하지만 이러한 작은 변화가 때때로 미래에 큰 영향을 미칠 수 있습니다.

기능 후 기능, 변경 후 변경, 구성 요소는 더 복잡해지는 경향이 있습니다. 우리가 그것을 주시하지 않는다면 그것들은 통제 불능이 될 것이고 그것은 우리로 하여금 변화를 두려워하게 만들 것입니다.

그렇기 때문에 구성 요소 계약에 주의해야 합니다. 그런데 그 계약은 소품을 통해 표현된다.

궁극적인 문제를 발견하는 한 가지 방법은 부울 소품(they will yell at you as you can read here)을 찾는 것입니다. 일반적인 경우는 렌더링 조건을 지정하는 방법으로 부울 소품을 사용하는 것입니다.



이 접근 방식에는 몇 가지 문제가 있습니다.
  • 구성 요소 계약이 복잡해지고 구성 요소의 상태를 평가하기 어려울 수 있습니다.
  • 구성 요소가 너무 많은 작업을 수행하는 증상일 수 있습니다.

  • 한 번 보자.

    복잡한 계약



    사용자가 사용자 이름을 사용하여 로그인할 수 있는 로그인 구성 요소를 만들어야 한다고 상상해 보십시오.

    import React from "react";
    
    function Login() {
      return (
        <div className="Login">
          <form>
            <p>
              <label>Username:</label>
              <input type="text" />
            </p>
            <p>
              <label>Password:</label>
              <input type="password" />
            </p>
            <p>
              <input type="submit" value="Log In" />
            </p>
          </form>
        </div>
      );
    }
    
    export default Login;
    


    어느 날 로그인 구성 요소를 검토하여 소비자가 사용자 이름 또는 이메일을 사용하여 로그인할지 여부를 결정할 수 있도록 해야 합니다. 이를 달성하기 위한 빠른 수정은 소비자가 이메일을 선호하는 경우 boolean prop으로 구성 요소를 만드는 것입니다.

    import React from "react";
    import PropTypes from "prop-types";
    
    function Login({ usingEmail }) {
      return (
        <div className="Login">
          <form>
            <p>
              <label>{usingEmail ? "Email:" : "Username:"}</label>
              <input type={usingEmail ? "email" : "text"} />
            </p>
            <p>
              <label>Password:</label>
              <input type="password" />
            </p>
            <p>
              <input type="submit" value="Log In" />
            </p>
          </form>
        </div>
      );
    }
    
    Login.propTypes = {
      usingEmail: PropTypes.bool,
    };
    
    export default Login;
    


    이제 언젠가 사용자가 전화번호로도 로그인할 수 있다고 상상해 보십시오. 이제 문제가 생겼습니다.

    부울 플래그는 세 가지 변형을 지원하도록 확장할 수 없으며 동일한 전략에 따라 모순되는 부울 소품을 얻게 됩니다. 구성 요소 소비자는 예를 들어 사용자 이름과 전화 로그인으로 구성 요소를 구성할 수 있습니다.

    import React from "react";
    import PropTypes from "prop-types";
    
    function Login({ usingEmail, usingPhoneNumber }) {
      return (
        <div className="Login">
          <form>
            <p>
              <label>
                {usingEmail ? "Email:" : usingPhoneNumber ? "Phone" : "Username:"}
              </label>
              <input
                type={usingEmail ? "email" : usingPhoneNumber ? "tel" : "text"}
              />
            </p>
            <p>
              <label>Password:</label>
              <input type="password" />
            </p>
            <p>
              <input type="submit" value="Log In" />
            </p>
          </form>
        </div>
      );
    }
    
    Login.propTypes = {
      usingEmail: PropTypes.bool,
      usingPhoneNumber: PropTypes.bool,
    };
    
    export default Login;
    


    부울 플래그가 있는 계약은 복잡하고 소비자에게 나쁜 UX를 제공합니다.

    구성 요소 서명을 복잡하게 만들고 이 구성 요소가 한 가지 이상의 작업을 수행한다고 소리칩니다. 플래그가 "True"이면 한 가지 작업을 수행하고 플래그가 "False"이면 다른 작업을 수행합니다. 이 예에서 최악의 상황은 소비자가 두 props가 모두 "True"일 때 무엇을 기대해야 할지 모른다는 것입니다.

    그래서 뭘 할건데?



    간단한 해결책은 부울보다 열거형을 선호하는 것입니다. 부울은 확장 가능하며 명확한 의도를 설명합니다.

    import React from "react";
    import PropTypes from "prop-types";
    
    const USER_IDENTIFIFICATION_TYPES = {
      USERNAME: "username",
      EMAIL: "email",
      PHONENUMBER: "phone",
    };
    
    function Login({ userIdentificationType }) {
      const shouldUseEmail =
        userIdentificationType === USER_IDENTIFIFICATION_TYPES.EMAIL;
      const shouldUsePhone =
        userIdentificationType === USER_IDENTIFIFICATION_TYPES.PHONENUMBER;
    
      return (
        <div className="Login">
          <form>
            <p>
              <label>
                {shouldUseEmail ? "Email:" : shouldUsePhone ? "Phone" : "Username:"}
              </label>
              <input
                type={shouldUseEmail ? "email" : shouldUsePhone ? "tel" : "text"}
              />
            </p>
            <p>
              <label>Password:</label>
              <input type="password" />
            </p>
            <p>
              <input type="submit" value="Log In" />
            </p>
          </form>
        </div>
      );
    }
    
    Login.propTypes = {
      userIdentificationType: PropTypes.oneOf(
        Object.values(USER_IDENTIFIFICATION_TYPES)
      ),
    };
    
    Login.defaultProps = {
      userIdentificationType: USER_IDENTIFIFICATION_TYPES.USERNAME,
    };
    
    export default Login;
    


    보시다시피 계약 문제를 수정했지만 이 구성 요소가 너무 많은 작업을 수행하고 있습니다.

    신 구성 요소



    계약 복잡성 외에도 부울 소품은 구성 요소가 너무 많은 일을 하는 신 구성 요소일 수 있다는 증상입니다.

    그래서 뭘 할건데?



    신의 구성 요소가 있다는 것을 알게 되면 구성 요소를 분리해야 합니다.

    이 로그인 구성 요소 예제에서는 예를 들어 다음과 같은 내부 세부 정보를 캡슐화하기 위해 세 가지 구성 요소를 만들 수 있습니다.
  • 사용자 이름로그인
  • 이메일 로그인
  • 전화번호 로그인

  • 기본 로그인 구성 요소




    import React from "react";
    import PropTypes from "prop-types";
    
    function Login({ children }) {
      return (
        <div className="Login">
          <form>
            <p>{children}</p>
            <p>
              <label>Password:</label>
              <input type="password" />
            </p>
            <p>
              <input type="submit" value="Log In" />
            </p>
          </form>
        </div>
      );
    }
    
    Login.propTypes = {
      children: PropTypes.node,
    };
    
    export default Login;
    


    사용자 이름 로그인 구성 요소




    import React from "react";
    
    import Login from "./Login";
    
    function UsernameLogin() {
      return (
        <Login>
          <label>Username:</label>
          <input type="text" />
        </Login>
      );
    }
    
    export default UsernameLogin;
    


    이메일 로그인 구성 요소




    import React from "react";
    
    import Login from "./Login";
    
    function EmailLogin() {
      return (
        <Login>
          <label>EmailLogin:</label>
          <input type="email" />
        </Login>
      );
    }
    
    export default EmailLogin;
    


    전화 로그인 구성 요소




    import React from "react";
    
    import Login from "./Login";
    
    function PhoneNumberLogin() {
      return (
        <Login>
          <label>Phone:</label>
          <input type="tel" />
        </Login>
      );
    }
    
    export default PhoneNumberLogin;
    


    이렇게 하면 구성 요소가 한 가지 작업을 잘 수행할 수 있습니다.

    도움이 되었기를 바랍니다. 이와 같은 더 많은 팁을 얻으려면 저를 팔로우하고 계속 연락합시다!

    좋은 웹페이지 즐겨찾기