[실전] 9. 심층 React 상태 관리 및 Redux 메커니즘(3) —— React17+React Hook+TS4 모범 사례, Jira 엔터프라이즈급 프로젝트 모방(18)


학습 콘텐츠 소스: React + React Hook + TS Best Practice - MOOC


원래 튜토리얼과 비교하여 연구 초기(2023.03)에 최신 버전을 사용했습니다.

안건 버전
반응 및 반응 돔 ^18.2.0
반응 라우터 및 반응 라우터 돔 ^6.11.2
개미 ^4.24.8
@commitlint/cli & @commitlint/config-conventional ^17.4.4
eslint-config-prettier ^8.6.0
에스키모 개의 ^8.0.3
린트 스테이징 ^13.1.2
더 예쁘다 2.8.4
json 서버 0.17.2
craco-less ^2.0.0
@craco/craco ^7.1.0
질문 ^6.11.0
데이즈 ^1.11.7
반응 헬멧 ^6.1.0
@유형/반응 헬멧 ^6.1.6
반응 쿼리 ^6.1.0
@welldone-software/why-d-you-render ^7.0.1
@감정/반응 및 @감정/스타일 ^11.10.6

구체적인 구성, 작동 및 내용이 다르며 "피트"도 다릅니다. . .


1. 프로젝트 시작: 프로젝트 초기화 및 구성

2. React 및 Hook 애플리케이션: 프로젝트 목록 구현

3. TS 적용 : JS 갓 어시스트 - 강형

4. JWT, 사용자 인증 및 비동기 요청


5. CSS는 실제로 매우 간단합니다. CSS-in-JS로 스타일을 추가하세요.


6. 사용자 경험 최적화 - 로딩 및 오류 상태 처리



7. 후크, 라우팅 및 URL 상태 관리



8. 사용자 선택기 및 항목 편집 기능


9. 심층 React 상태 관리 및 Redux 메커니즘

1&2

3&4

5. redux 사용법 소개

JavaScript 앱의 예측 가능한 상태 컨테이너 - JavaScript 애플리케이션의 예측 가능한 상태 컨테이너

  • reduxreact와 직접적인 관련이 없으며 다른 vuejs/ts 프로젝트 에서도 사용할 수 있습니다.
  • redux상태 컨테이너라고 하는 것이 상태 관리 도구보다 더 정확합니다.

html + js다음으로 일상적으로 사용하는 공식 redux사례를 살펴보자.

예시/카운터 바닐라

<!DOCTYPE html>
<html>
  <head>
    <title>Redux basic example</title>
    <script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
  </head>
  <body>
    <div>
      <p>
        Clicked: <span id="value">0</span> times
        <button id="increment">+</button>
        <button id="decrement">-</button>
        <button id="incrementIfOdd">Increment if odd</button>
        <button id="incrementAsync">Increment async</button>
      </p>
    </div>
    <script>
      function counter(state, action) {
    
    
        if (typeof state === 'undefined') {
    
    
          return 0
        }

        switch (action.type) {
    
    
          case 'INCREMENT':
            return state + 1
          case 'DECREMENT':
            return state - 1
          default:
            return state
        }
      }

      var store = Redux.createStore(counter)
      var valueEl = document.getElementById('value')

      function render() {
    
    
        valueEl.innerHTML = store.getState().toString()
      }

      render()
      store.subscribe(render)

      document.getElementById('increment')
        .addEventListener('click', function () {
    
    
          store.dispatch({
    
     type: 'INCREMENT' })
        })

      document.getElementById('decrement')
        .addEventListener('click', function () {
    
    
          store.dispatch({
    
     type: 'DECREMENT' })
        })

      document.getElementById('incrementIfOdd')
        .addEventListener('click', function () {
    
    
          if (store.getState() % 2 !== 0) {
    
    
            store.dispatch({
    
     type: 'INCREMENT' })
          }
        })

      document.getElementById('incrementAsync')
        .addEventListener('click', function () {
    
    
          setTimeout(function () {
    
    
            store.dispatch({
    
     type: 'INCREMENT' })
          }, 1000)
        })
    </script>
  </body>
</html>

예전에 썼던 use-undo와 많이 비슷한 느낌이랄까요?

예측 가능: 동일한 입력 매개변수에 대해 함수의 반환 값과 그 영향이 확실합니다.


Redux에서 해야 할 일과 하지 말아야 할 일

  • reduxin stateimmutable교체만 가능하고 변경할 수 없습니다. 디자인 개념은 react의 것과 state일치하며 모두 업데이트 여부를 ===비교하는 데 사용됩니다.state
  • reduxin 은 reducer순수 함수여야 합니다. 그러나 이것은 비동기 함수를 사용할 수 없다는 의미가 아니라 비동기 함수의 콜백에서 사용할 수 있습니다.dispatch

그냥 원래 상태로 돌아가지 않고 교체하는 이유는 무엇입니까?

두 자바스크립트 객체의 모든 속성이 정확히 같은지 여부를 비교하는 유일한 방법은 심층 비교를 수행하는 것이므로 실제 응용 프로그램에서는 심층 비교 코드가 매우 커서 많은 성능을 소비하고 따라서 효과적인 솔루션은 변경 사항이 발생할 때마다 개발자가 새 개체를 반환하도록 규정하는 것입니다.


순수함수란?

  1. 외부 환경의 상태에 의존하지 않고 입력 매개변수에만 의존합니다. 동일한 입력은 항상 동일한 출력을 반환합니다.
  2. 부작용 없음 - 함수의 입력 값을 수정하지 않으며 네트워크 요청, 입력 및 출력 장치 또는 데이터 변이(돌연변이)와 같은 관찰 가능한 부작용을 일으키지 않습니다.

6. react-redux 및 HoC

컨테이너 구성 요소는 프레젠테이션 구성 요소와 분리됩니다.

7. [확장 학습] React Hook의 역사

다음은 코스웨어의 원본 텍스트입니다.

후크의 역사

React 팀은 처음부터 React의 코드 재사용성에 많은 관심을 기울였습니다.
.
코드 재사용성에 대한 그들의 솔루션은 Mixin, HOC, Render Prop, 지금까지 Custom Hook 까지 거쳤습니다
.
그래서 Custom Hook은 Custom Hook 개발에 풍부한 경험을 가진 많은 개발자가 없는 경우에도 갑자기 탄생한 제품이 아닙니다. Hook이 어떻게 생겨났고 React에서 어떤 역할을 하는지 알 수 있습니다
.
이 디자인 아이디어를 이해하지 못한다면 Custom Hook을 깊이 이해할 수 없습니다.오늘 함께 배워봅시다.

1. 믹스인
var SetIntervalMixin = {
     
     
  componentWillMount: function() {
     
     
    this.intervals = [];
  },
  setInterval: function() {
     
     
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
     
     
    this.intervals.forEach(clearInterval);
  }
};

var createReactClass = require('create-react-class');

var TickTock = createReactClass({
     
     
  mixins: [SetIntervalMixin], //使用mixin
  getInitialstate: function() {
     
     
    return {
     
     seconds: 0;},
  },
  componentDidMount: function() {
     
     
    this.setInterval(this.tick, 1000);//调用mixin上的方法
  }
})

이점:

  1. 코드를 재사용하는 목적을 수행합니다.

결점:

  1. 암시적 종속성이며 암시적 종속성은 React에서 나쁜 것으로 간주됩니다.
  2. 이름 충돌 문제
  3. ReactcreateClass에서만 작동할 수 있으며 ES6 ClassComponent를 지원하지 않습니다.
  4. 현실적으로는 유지하기 어렵다고 합니다
    .

React 공식 웹 사이트에서 더 이상 사용되지 않는 것으로 표시되었으며 공식 불만 사항은 여기에 있습니다.

2. 임시

2015년부터 React 팀은 Mixin이 권장되지 않으며 모든 사람이 HOC 모드를 사용하도록 권장한다고 발표했습니다
.
HOC는 '데코레이터 모드'를 사용하여 코드를 재사용합니다.

function withWindowWidth(BaseComponent) {
     
     
  class DerivedClass extends ReactComponent {
     
     
    state = {
     
     
      windowWidth: window.innerwidth,
    }
    onResize = () => {
     
     
      this.setState({
     
     
        windowWidth: window.innerwidth,
      })
    }
    componentDidMount() {
     
     
      window.addEventListener(resizethisonResize)
    }
    componentWillUnmount(){
     
     
      window.removeEventListener(resizethisonResize)
    }
    render() {
     
     ...}
  }
}

여기에서 컨테이너 프레지던트 및 클래식 컨테이너 구성 요소의 분리가 시작됩니다.
.
다음은 HOC 컨테이너 구성 요소와 프레젠테이션 구성 요소를 분리하는 가장 고전적인 사례입니다. Redux의 연결 예제 코드입니다.

export const createInfoScreen = (ChildComponent, fetchData, dataName) => {
     
     
  class HOComponent extends Comnonent {
     
     
    state = {
     
      counter: 0 }
    handleIncrementCounter = () => {
     
     
      this.setState({
     
      counter:this.state.counter + 1 });
    }
    componentDidMount(){
     
     
      this.props.fetchData();
    }
    render() {
     
     
      const {
     
      data={
     
     },isFetching, error } = this.props[dataName];
      if (isFetching) {
     
     
        return(
          <div>Loading</div>
        );
      }
      if (error) {
     
     
        return(
          <div>Something is wrongPlease tryagain!</div>
          ...
        )
      }
    }
  }
}

이점

  1. Class Component를 포함한 모든 구성 요소에서 작업 가능
  2. 그것이 옹호하는 컨테이너 구성 요소와 디스플레이 구성 요소의 분리 원칙이 달성되었습니다: 관심의 분리

결점

  1. 직관적이지 않은, 읽기 어려운
  2. 이름 충돌
  3. 구성 요소는 레이어별로 중첩됩니다.
3. 소품 렌더링

2017년부터 Render Prop이 인기를 끌었습니다.
Render
Prop은 '프록시 패턴'을 사용하여 코드를 재사용합니다.

class WindowWidth extends React.Component {
     
     
  propTypes = {
     
     
    children: PropTypes.func.isRequired
  }
  state = {
     
     
    windowWidth: window.innerWidth,
  }
  onResize = () => {
     
     
    this.setState({
     
     
      windowWidth: window.innerWidth,
    })
  }
  componentDidMount() {
     
     
    window.addEventListener('resize', this.onResize);
  }
  componentWillUnmount() {
     
     
    window.removeEventListener('resize', this.onResize);
  }
  ...
 }

React Router는 또한 다음 API 설계를 채택합니다.

<Route path = "/about" render= {
     
      (props) => <About {
     
     ...props} />}>

이점:

  1. 유연한

결점:

  1. 읽기 어렵다, 이해하기 어렵다
4. 후크

2018년에 React 팀은 코드를 재사용하는 새로운 방법인 React Hook을 발표했습니다.
핵심 변경 사항 은
기능 구성 요소가 자신의 상태를 저장할 수 있도록 하는 것입니다. 그 전에는 기능 구성 요소가 자신의 상태를 가질 수 없었습니다.

변경을 통해 React 구성 요소의 논리를 일반 함수인 것처럼 추상화할 수 있습니다.
.
이행 원칙: 폐쇄

import {
     
      useState, useEffect } from "react";
const useWindowsWidth = () => {
     
     
  const [isScreenSmall, setIsScreenSmall] = useState(false)

  let checkScreenize = () => {
     
     
    setIsScreenSmall(window.innerWidth < 600);
  };
  useEffect(()=> {
     
     
    checkscreenSize();
    window.addEventListener("resize", checkscreenSize);
    return () => window.removeEventListener("resize", checkScreenSize);
  }, []);

  return isScreenSmall
};

export default useWindowsWidth
import React from 'react'
import useWindowWidth from'./useWindowWidth.js'

const MyComponent = () => {
     
     
  const onSmallScreen = useWindowWidth;

  return (
    // Return some elements
  )
}

이점:

  1. 논리를 추출하는 것은 매우 쉽습니다.
  2. 매우 쉽게 결합
  3. 매우 읽기 쉬운
  4. 이름 충돌 문제 없음

결점

  1. 후크에는 자체 사용 제한이 있습니다. 구성 요소의 최상위 수준에서만 사용할 수 있으며 구성 요소에서만 사용할 수 있습니다.
  2. 폐쇄가 원칙이므로 드물게 이해할 수 없는 문제가 발생할 수 있습니다.

8. redux-thunk가 필요한 이유는 무엇입니까?

reduxjs/redux-thunk: Redux용 Thunk 미들웨어

핵심 소스 코드:

import type {
    
     Action, AnyAction } from 'redux'

import type {
    
     ThunkMiddleware } from './types'

export type {
    
    
  ThunkAction,
  ThunkDispatch,
  ThunkActionDispatch,
  ThunkMiddleware
} from './types'

/** A function that accepts a potential "extra argument" value to be injected later,
 * and returns an instance of the thunk middleware that uses that value
 */
function createThunkMiddleware<
  State = any,
  BasicAction extends Action = AnyAction,
  ExtraThunkArg = undefined
>(extraArgument?: ExtraThunkArg) {
    
    
  // Standard Redux middleware definition pattern:
  // See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware
  const middleware: ThunkMiddleware<State, BasicAction, ExtraThunkArg> =
    ({
     
      dispatch, getState }) =>
    next =>
    action => {
    
    
      // The thunk middleware looks for any functions that were passed to `store.dispatch`.
      // If this "action" is really a function, call it and return the result.
      if (typeof action === 'function') {
    
    
        // Inject the store's `dispatch` and `getState` methods, as well as any "extra arg"
        return action(dispatch, getState, extraArgument)
      }

      // Otherwise, pass the action down the middleware chain as usual
      return next(action)
    }
  return middleware
}

export const thunk = createThunkMiddleware()

// Export the factory function so users can create a customized version
// with whatever "extra arg" they want to inject into their thunks
export const withExtraArgument = createThunkMiddleware
  • 디스패치는 비동기 작업에 배치될 수 있습니다.
  • redux-thunk 또는 기타 미들웨어를 사용하면 비동기 작업을 동기 작업만큼 우아하게 만들 수 있으며 비동기 및 기타 작업은 별도로 분리됩니다.

일부 참조 노트는 아직 초안 단계에 있으므로 계속 지켜봐 주시기 바랍니다. . .

추천

출처blog.csdn.net/qq_32682301/article/details/132064487