Javascript - функції Pure vs Nempure


12

Я пройшов дефініції двох таких як:

Чисті функції - це ті, які не намагаються змінити свої входи і завжди повертають однаковий результат для тих же входів.

Приклад

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

І незрозуміла функція - це та, яка змінює власний вклад.

Приклад

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

Визначення та фрагменти коду, взяті з офіційних документів ReactJs .

Тепер хтось може сказати мені, як я можу зробити деякі помилки в React / Redux , щоб використовувати нечисті функції там, де потрібні чисті функції?


4
Нечисті функції мають побічні ефекти. Щось на зразок window.getElementByIdтощо, тому виконання однакової функції з тими ж параметрами може мати різні результати залежно від побічних ефектів. Ось де редукція не зможе.
Домінік

Відповіді:


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. combineReducersУтиліта Redux перевіряє наявність змін.
  2. connectМетод React-Redux генерує компоненти, які перевіряють зміни еталонів як для кореневого стану, так і для повернених значень від mapStateфункцій, щоб побачити, чи справді обгорнутий компонент потребує повторного відтворення.
  3. Налагодження часу в дорозі вимагає, щоб у редуктора не pure functionsбуло побічних ефектів, щоб ви могли правильно переходити між різними станами.

Ви можете легко порушити вищевказані три, використовуючи нечисті функції в якості редукторів.

Далі взято безпосередньо з редукційних документів:

Це називається редуктором, тому що це тип функції, який ви перейшли б 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;
}

У випадку Реагу / Редукс

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

Цього робити не слід . Все, що потрібна функція підключення або функція редуктора, повинна надаватися через аргумент або записуватися в межах її функції. Він ніколи не повинен потрапляти ззовні.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.