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


12

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

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

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

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

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

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

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


4
불순한 기능에는 부작용이 있습니다. 비슷해 window.getElementById등 때문에 동일한 파라미터와 같은 기능을 실행은 부작용에 따라 다른 결과를 가질 수있다. redux가 실패하는 곳입니다.
도미니크

답변:


10

반응과 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 호출이 없습니다. 돌연변이가 없습니다. 계산 만하면됩니다.


7

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

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

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
  }
}

5

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
   }
  }
}

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.