Javascript - Fungsi murni vs tidak murni

12

Saya telah melalui definisi keduanya seperti:

Fungsi murni adalah fungsi yang tidak berusaha mengubah inputnya, dan selalu mengembalikan hasil yang sama untuk input yang sama.

Contoh

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

Dan fungsi yang tidak murni adalah yang mengubah inputnya sendiri.

Contoh

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

Cuplikan definisi dan kode diambil dari dokumen resmi ReactJs .

Sekarang, bisakah seseorang memberi tahu saya, bagaimana saya bisa membuat beberapa kesalahan dalam React / Redux , untuk menggunakan fungsi tidak murni di mana fungsi murni diperlukan?

MuhammadUmar Farooq
sumber
4
Fungsi yang tidak murni memiliki efek samping. Sesuatu seperti window.getElementByIddll sehingga menjalankan fungsi yang sama dengan parameter yang sama dapat memiliki hasil yang berbeda tergantung pada efek sampingnya. Di situlah redux akan gagal.
Dominik

Jawaban:

10

Bereaksi dan Reduxkeduanya membutuhkan fungsi murni ditambah dengan imutabilitas untuk berjalan dengan cara yang dapat diprediksi.

Jika Anda tidak mengikuti dua hal ini, aplikasi Anda akan memiliki bug, yang paling umum React/Reduxtidak dapat melacak perubahan dan tidak dapat membuat ulang saat state/propperubahan Anda .

Dalam hal Bereaksi, pertimbangkan contoh berikut:

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();
}

Negara dipegang oleh objek negara yang hanya menambahkan properti. Aplikasi ini membuat properti aplikasi. Seharusnya tidak selalu membuat negara ketika sesuatu terjadi tetapi harus memeriksa apakah perubahan terjadi pada objek negara.

Seperti itu, kita memiliki fungsi efek, pure functionyang kita gunakan untuk memengaruhi kondisi kita. Anda melihat bahwa ia mengembalikan status baru ketika status diubah dan mengembalikan status yang sama ketika tidak diperlukan modifikasi.

Kami juga memiliki shouldUpdatefungsi yang memeriksa menggunakan operator === apakah kondisi lama dan kondisi baru sama.

Untuk membuat kesalahan dalam hal Bereaksi, Anda sebenarnya dapat melakukan hal berikut:

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

Anda juga dapat membuat kesalahan dengan mengatur negara secara langsung dan tidak menggunakan effectsfungsi.

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

Hal di atas tidak boleh dilakukan dan hanya effectsfungsi yang harus digunakan untuk memperbarui status.

Dalam hal Bereaksi, kami menyebutnya effectssebagai setState.

Untuk Redux:

  1. combineReducersUtilitas Redux memeriksa perubahan referensi.
  2. connectMetode React-Redux menghasilkan komponen yang memeriksa perubahan referensi untuk kondisi root dan nilai kembali dari mapStatefungsi untuk melihat apakah komponen yang dibungkus benar-benar perlu di-render ulang.
  3. Debugging perjalanan waktu mengharuskan peredam dilakukan pure functionstanpa efek samping sehingga Anda dapat melompat dengan benar di antara berbagai kondisi.

Anda dapat dengan mudah melanggar ketiga di atas dengan menggunakan fungsi tidak murni sebagai peredam.

Berikut ini diambil langsung dari redux docs:

Ini disebut peredam karena itu jenis fungsi yang akan Anda masuki Array.prototype.reduce(reducer, ?initialValue).
Sangat penting bahwa peredam tetap murni. Hal yang tidak boleh Anda lakukan di dalam peredam:

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

Dengan argumen yang sama, harus menghitung status berikutnya dan mengembalikannya. Tidak ada kejutan. Tidak ada efek samping. Tidak ada panggilan API. Tidak ada mutasi. Hanya perhitungan.

Utsav Patel
sumber
7

Sederhananya negara tidak dapat dimutasi. Sebuah instance baru dari negara harus dikembalikan setiap kali ada perubahan

Kode ini tidak benar:

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

Kode ini ketika ditulis sebagai fungsi murni di bawah, Ini mengembalikan instance baru dari array yang tidak mengubah array itu sendiri. Inilah alasan Anda harus menggunakan perpustakaan seperti immer untuk menangani ketidakberdayaan

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
  }
}
muddassir
sumber
5

Anda dapat membuat fungsi murni tidak murni dengan menambahkan panggilan API atau menulis kode yang menghasilkan efek samping.

Fungsi murni harus selalu tepat dan jelas, dan seharusnya tidak mengharuskan Anda untuk merujuk 3 atau 4 fungsi lainnya untuk memahami apa yang terjadi.

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

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

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

Ini seharusnya tidak dilakukan . Segala sesuatu yang dibutuhkan fungsi koneksi atau fungsi peredam harus disediakan melalui argumen atau dituliskan dalam fungsinya. Seharusnya tidak pernah dari luar.

Pushkin
sumber