[javascript] 자바 스크립트-순수 대 불순 함수

나는 두 가지의 정의를 겪었다.

순수한 함수는 입력을 변경하지 않고 항상 동일한 입력에 대해 동일한 결과를 반환하는 함수입니다.

function sum(a, b) {
  return a + b;
}

그리고 Impure 기능은 자체 입력을 변경하는 기능입니다.

function withdraw(account, amount) {
  account.total -= amount;
}

ReactJs 공식 문서 에서 가져온 정의 및 코드 스 니펫 .

이제 누군가가 React / Redux 에서 실수를 하여 순수한 함수가 필요한 불순한 함수를 어떻게 사용할 수 있는지 말해 줄 수 있습니까?



답변

반응과 Redux둘 다 불변성과 결합하여 예측 가능한 방식으로 실행되는 순수한 기능이 필요합니다.

이 두 가지 사항을 따르지 않으면 앱에 버그가 있으며, 가장 일반적인 것은 React/Redux변경 사항을 추적 할 수없고 변경 사항을 다시 렌더링 할 수없는 state/prop것입니다.

React와 관련하여 다음 예제를 고려하십시오.

let state = {
    add: 0,
}

function render() {
    //...
}
//pure function
function effects(state,action) {
//following immutability while updating state, not directly mutating the state.
    if(action == 'addTen') {
        return {...state, add: state.add + 10} 
    }
    return state;
}

function shouldUpdate(s) {
    if(s === state){
        return false
    }
    return true
}

state = effects(state, 'addTen')if(shouldUpdate(state)) {
    render();
}

상태는 속성 만 추가 된 상태 객체에 의해 유지됩니다. 이 앱은 앱 속성을 렌더링합니다. 상황이 발생할 때 항상 상태를 렌더링하지는 않지만 상태 객체에서 변경이 발생했는지 확인해야합니다.

이와 같이, 우리는 pure function상태에 영향을주기 위해 사용 하는 효과 함수 를 가지고 있습니다. 상태가 변경 될 때 새 상태를 반환하고 수정이 필요하지 않은 경우 동일한 상태를 반환합니다.

또한 shouldUpdate=== 연산자를 사용하여 이전 상태와 새 상태가 같은지 검사 하는 기능 도 있습니다 .

React와 관련하여 실수를하려면 실제로 다음을 수행하십시오.

function effects(state,action) {

  doRandom(); // effects should only be called for updating state.
             // Doing any other stuff here would make effects impure.

    if(action == 'addTen') {
        return {...state, add: state.add + 10}
    }
    return state;
}

effects기능을 사용하지 않고 상태를 직접 설정하여 실수를 할 수도 있습니다.

function doMistake(newValue) {
    this.state = newValue
}

위의 작업을 수행 effects해서는 안되며 상태 만 업데이트하려면 기능 만 사용해야합니다.

React의 관점에서 우리는 effects로 전화 합니다 setState.

Redux의 경우 :

  1. Redux의 combineReducers유틸리티는 참조 변경 사항을 확인합니다.
  2. React-Redux의 connect방법은 루트 상태와 mapState함수 의 반환 값에 대한 참조 변경 사항을 확인 하여 랩핑 된 구성 요소를 실제로 다시 렌더링 해야하는지 확인하는 구성 요소를 생성합니다 .
  3. 시간 이동 디버깅에서는 리듀서 pure functions에 부작용이 없어서 다른 상태간에 올바르게 이동할 수 있어야합니다.

불완전한 기능을 감속기로 사용하면 위의 세 가지를 쉽게 위반할 수 있습니다.

다음은 redux 문서에서 직접 가져온 것입니다.

전달하는 함수 유형이기 때문에 리듀서라고합니다 Array.prototype.reduce(reducer, ?initialValue).

감속기가 순수한 상태를 유지하는 것이 매우 중요합니다. 감속기 안에서는 절대로하지 말아야 할 것들 :

Mutate its arguments;
Perform side effects like API calls and routing transitions;
Call non-pure functions, e.g. Date.now() or Math.random().

동일한 인수가 주어지면 다음 상태를 계산하여 반환해야합니다. 놀랍지 않습니다. 부작용이 없습니다. API 호출이 없습니다. 돌연변이가 없습니다. 계산 만하면됩니다.


답변

간단히 말해서 상태를 변경할 수 없습니다. 변경이있을 때마다 상태의 새로운 인스턴스를 반환해야합니다.

이 코드는 올바르지 않습니다 :

const initialStates = {    
  items: ['item1']
}

export const ItemMaster = (state = initialStates, action) => {    
  switch (action.type) {
    case TYPES.ADD_ITEM:            
    {
        state.items.push(action.item)
        return state
    }
    default:
      return state
  }
}

이 코드는 아래 순수한 함수로 작성 될 때 실제 배열 자체를 수정하지 않는 배열의 새 인스턴스를 반환합니다. 불변성을 처리하기 위해 immer 와 같은 라이브러리를 사용해야하는 이유입니다.

const initialStates = { 
  items: ['item1']
}

export const ItemMaster = (state = initialStates, action) => {    
  switch (action.type) {
    case TYPES.ADD_ITEM:            
    {

        state = {...state,items:state.items.concat(action.item)}
        return state
    }
    default:
      return state
  }
}


답변

API 호출을 추가하거나 부작용을 일으키는 코드를 작성하여 순수한 기능을 불완전하게 만들 수 있습니다.

순수한 기능은 항상 정확하고 설명이 필요하며 진행중인 상황을 이해하기 위해 3 ~ 4 개의 다른 기능을 참조 할 필요는 없습니다.

// Pure Function
function USDtoEUR(USD, todayRate) {
  return USD * todayRate;
}

// Impure Function 
function USDtoEUR(USD) {
  const todayRate = getTodayRate();
  return USD * todayRate;
}

React / Redux의 경우

const mapState = async state => {
  const { data } = await whatDoINeed()

  let mappedState = {}

  if (data.needDolphin) {
    mappedState.dolphin = state.dolphin
  }

  if (data.needShark) {
    mappedState.shark= state.shark
  }

  return mappedState;
}

// Or for Redux Reducer
// Bad
{
  setData: (state, payload) => {
   const set = whatToSet()
   return {
     ...state,
     set.dolphin ? ...{ dolphin: payload.dolphin } : ...{},
     set.shark ? ...{ shark : payload.shark } : ...{},
   }
  }
}

// Good
{
  setData: (state, payload) => {
   return {
     ...state,
     // Just send only the things need
     // to be sent
     ...payload
   }
  }
}

이 작업을 수행하지 않아야합니다 . 연결 기능 또는 감속기 기능에 필요한 모든 것은 인수를 통해 제공되거나 해당 기능 내에 작성되어야합니다. 절대 외부에서 나오지 않아야합니다.


답변