Redux'un durum işlevlerine neden indirgeyiciler denir?


82

Bu, resmi Redux belgelerinin bir parçasıdır :

İndirgeyici olarak adlandırılır çünkü bu, geçeceğiniz işlev türüdür Array.prototype.reduce(reducer, ?initialValue)

Bana pek mantıklı gelmiyor. Biri bana neden aslında redüktör olarak adlandırıldığını açıklayabilir mi? Varsayılan bir değer döndürmeleri (veya varsayılan bir bağımsız değişken değerine sahip olmaları), onları IMHO indirgeyici yapmaz.


6
İndirgeyicilerdir, çünkü geçtiğiniz işlev gibi davranırlar reduce, varsayılan değere ve başka bir değere erişimi vardır ve size potansiyel olarak dönüştürülmüş varsayılan değerinizi geri verir. state -> action -> state
azium

2
başka bir isimde bir gül ... muhtemelen pazarlama; harita / azaltma artık
moda

1
bu yüzden kendinizi düşünmeye başlamalısınız ve bir çerçeveye güvenmemelisiniz. Çerçeve çalışması çoğunlukla, internet kullanıcıları tarafından uyarlanan bir problemin nasıl çözüleceği konusunda kendi vizyonuna sahip bir veya birkaç geliştiricinin çalışmasıdır. Bazı çerçeveler bunu doğru anladı, ancak çoğu değil. bir öpücüğün fırtınası, aynı veya daha az bir çözüm değildir. Bu, oradaki birçok kişiye sadece bir örnek.
Codebeat

Yanıtlar:


71

Varsayılan bir değer döndürmeleri (veya varsayılan bir bağımsız değişken değerine sahip olmaları), onları IMHO indirgeyici yapmaz.

Redüktörler yalnızca varsayılan değerleri döndürmezler. Her zaman devletin birikimini döndürürler (önceki ve mevcut tüm eylemlere dayanarak).

Bu nedenle, devletin indirgeyicisi olarak hareket ederler . Redux düşürücü her çağrıldığında, eyleme geçilir (state, action). Bu durum daha sonra eyleme göre azaltılır (veya biriktirilir) ve ardından bir sonraki durum döndürülür. Bu, klasik foldveya reduceişlevin bir döngüsüdür .

@Azium'un özetlediği gibi state -> action -> state.


7
Bu mantıkla Humm, indirgeyicilerden ziyade artırıcılar olarak adlandırılmamalı mı? Hiçbir verinin eklenmesi
azalmıyor

16
@JamieHutber Bu bağlamda redüktörün anlamını biraz özlediğinizi düşünüyorum. redüktör, bir öğe akışını (veya koleksiyonunu) alıp bunları tek bir öğede birleştirmektir. Bu durumda, tüm eylemler (zaman yoluyla) öğeler koleksiyonudur ve durum tek öğedir. Mantıklı olmak?
Davin Tryon

7
lol şimdi anlıyorum. Yani temelde sadece onları sıralıyor. Neden birleşme
demiyorsunuz

20
Tanrıya şükür, bunu yazdığım sırada indirgeyicinin bu yazıda en az 2.000 görüşe sahip olmadığını düşünen tek kişi ben değilim. Birisinin neden indirgeyici olarak adlandırıldığını kazma çabasını artırmaya istekli olması, aslında biraz yanlış olduğu anlamına gelmiyor mu? Array.prototype.reduce'a ileteceğiniz işlev türü olduğu için buna indirgeyici deniyorsa, turuncuya bir meyve sıkacağı diyelim çünkü turuncuyu object.prototype.juicer'a aktarıyoruz, yoksa ona meyve dememeli miyiz?
Yini

2
Katılıyorum, hiç de sezgisel bir isim değil. Mantıksal olarak, redüktör olarak adlandırılabilmesi için bir şeyi azaltması gerekir. Bir durumla birlikte bir dizi durum değişikliği alıp bunları aynı anda tek bir durumda birleştirseydi, o zaman sezgisel bir ad olurdu.
Peter Evan Deal

20

Uygulamanızdaki bir dizi eylemin bir liste veya belki daha çok bir akış gibi olduğunu düşünüyorsanız, daha mantıklı olabilir.

Bu uydurma örneği ele alalım:

['apple', 'banana', 'cherry'].reduce((acc, item) => acc + item.length, 0)

İlk argüman, formun bir işlevidir (Int, String) => Int. Bir başlangıç ​​değerinin yanı sıra, reduce"indirgeme işlevi" olarak adlandırılabilecek şeyi geçersiniz ve bir dizi öğe işlemenin sonucunu alırsınız. Dolayısıyla, azaltıcı işlevin sonucu değiştirmek için birbirini izleyen her bir öğeye ne yapıldığını açıkladığını söyleyebilirsiniz. Diğer bir deyişle, indirgeyici işlevi önceki çıktıyı ve sonraki değeri alır ve bir sonraki çıktıyı hesaplar.

Bu, bir Redux düşürücünün yaptığına benzer: önceki durumu ve mevcut eylemi alır ve bir sonraki durumu hesaplar.

Gerçek işlevsel programlama stilinde, argümanlara ve sonuca uygulanan anlamı kavramsal olarak silebilir ve sadece girdilerin ve çıktının "şekline" odaklanabilirsiniz.

Uygulamada, Redux düşürücüler tipik olarak ortogonaldir, çünkü belirli bir eylem için hepsinin aynı özelliklerde değişiklik yapmaması, sorumluluklarını bölmeyi ve çıktıyı toplamayı kolaylaştırır combineReducers.


Evet, haklısın, daha çok bir akış gibi eylemler hakkında düşündüğümde daha mantıklı geliyor. Harika, özür dilerim!
Anton Savchenko

Başlangıçta anladığım şey buydu, ancak şimdiye kadar gördüğüm mağaza uygulamalarının hiçbirinin bunu nasıl uyguladığı görünmüyor ...
Boris Callens

16

Daha önce de belirtildiği gibi, isim, fonksiyonel programlamada bir redüktör kavramı ile ilgilidir. Ayrıca Merriam-Webster sözlüğünde redüktör tanımını da yararlı bulabilirsiniz:

1 A. bir araya getirmek veya yakınlaşmaya neden olmak: birleştirmek (tüm soruları bire indirgemek)

İndirgeyici, eylemleri uygulama durumunu temsil eden tek bir nesnede birleştirir.


8

Bir redüktör azaltıcıya a denmesinin reducernedeni , sonucu elde etmek için bu eylemleri gerçekleştirmek için a collection of actionsve bir initial state(mağazanın) "azaltabilmeniz" içindir final state.

Nasıl? Buna cevap vermek için tekrar bir redüktör tanımlayayım:

Azaltır () metodu uygulanır function (reducer)bir karşı accumulatorve dizinin her bir değer (sol-sağ), tek bir değere düşürmek için.

Redux düşürücü ne işe yarar?

İndirgeyici, functionmevcut durumu ve bir eylemi alan ve bir sonraki duruma geri dönen bir saftır . Durumun accumulated, koleksiyondaki her eylem bu durumu değiştirmek için uygulandığına dikkat edin.

Böylece a verildiğinde collection of actions, indirgeyici, koleksiyonun her bir değerine uygulanır (soldan sağa). İlk seferinde initial value. Şimdi indirgeyici bu başlangıç ​​durumuna tekrar uygulanır ve bir sonraki duruma dönmek için ilk eylem. Ve bir sonraki koleksiyon öğesi (eylem), dizinin sonuna ulaşıncaya kadar current statealmak için her defasında uygulanır next state. Ve sonra anlarsın the final state. Ne kadar serin!


5

Yazar durumu, azaltma işlevinin toplayıcısı olarak düşünür. Ör:

Final State = [Action1, Action2, ..., ActionN].reduce(reducer, Initial State);

Azaltma fonksiyonu Fonksiyonel Programlamadan, "redüktör" adı da FP'den gelmektedir.

Bu adı burada kullanmayı sevmiyorum. Çünkü dünyayı eylemlerden sonra tek bir değer sonucu olarak görmüyorum. Buradaki durum bir nesnedir. Örneğin:

['eat', 'sleep'] === [addTodo('eat'), addTodo('sleep')].reduce(reducer, []);

Bu Redüktör hiçbir şeyi azaltmaz . Ve hiçbir şeyi azaltması ya da azaltmaması umrumda değil. Bunu Dönüştürücü olarak adlandırmak daha mantıklı olacaktır.


5

Redüktörlerin nereden geldiğini (fonksiyonel programlama) ve neden azaltıcı iş yaptıklarını biliyoruz (n girdi maddesini tek bir dönüş değerine düşür - bu da normal fonksiyonların yaptığı gibi). Ancak: İsim sadece bir isimdir, gülün bir gülün ismi olması gibi. Çok düşünme. Redux programcıları BT çalışanlarıdır, kendi bağlamlarına kilitlenmişlerdir ve bu mantıklıdır. Geri kalanımız mucidin mavi köpeğe sarı kedi deme hakkını kabul etmeliyiz ;-)


2

Onu nasıl desek Deducer şu andan itibaren. Yeni durumu, önceki duruma ve gelen eyleme göre çıkarır.


1

Azaltma aracı olarak azaltma olarak adlandırılmamalılar, bu işlevler çoğu zaman daha fazlasını yapar. ve sonra iade et


1

Bir Redux redüktörünün, kullandığınız fonksiyonla nasıl doğrudan eşleştiğini tam olarak göremedim reduce, bu yüzden işte nasıl eşleştiklerini görmek için birkaç örnek.

Öncelikle MDN Dizisinden standart bir indirgeyici ( MDN'de 'akümülatör' olarak adlandırılır) işlevi dokümantasyonu azaltın ve ardından ' Redux'a ihtiyacınız olmayabilir' blog gönderisininCounter.js sonunda Dan Abramov'un basitleştirilmiş bir örneği .

  • sum akümülatöre bir değer katar
  • reducer Akümülatöre / akümülatöre bir değer ekler / çıkarır.

Her iki durumda da burada 'durum' sadece bir tam sayıdır.

Eylemleri eyalette 'biriktiriyorsunuz'. Bu aynı zamanda herhangi bir JavaScript nesnesini değiştirmenin değişmez yoludur.

const sum = function(acc, val) {
    return acc + val;
};

const reducer = function(state, action) {
    switch (action) {
        case 'INCREMENT':
            return state + 1;
        case 'DECREMENT':
            return state - 1;
        default:
            return state;
    }
};

console.log('sum', [1, -1, 1].reduce(sum, 0));

console.log('reduce', ['INCREMENT', 'DECREMENT', 'INCREMENT'].reduce(reducer, 0));

console.log('sum', [1, 1, 1].reduce(sum, 0));

console.log('reduce', ['INCREMENT', 'INCREMENT', 'INCREMENT'].reduce(reducer, 0));


0

Diğer cevaplar, neden böyle adlandırıldığını iyi açıklıyor ama hadi daha fazla şeyi adlandırmayı deneyelim ...

const origState = 0;
const actionOperators = {
    increment: (origState) => origState++,
    decrement: (origState) => origState--,
};
const anOperator = (aState, anAction) => actionOperators[anAction](aState);
const actions = ['increment', 'decrement', 'increment'];
const finalState = actions.reduce(anOperator, origState);

İlk reduceolarak çağrılabilir use anOperator with every action name and accumulated state, starting with origState. Smalltalk'ta buna denir actions inject: origState into: anOperator. Peki operatöre aslında ne enjekte ediyorsunuz? OrigState VE eylem adları. Yani Smalltalk yönteminde bile isimler çok net değil.

actionOperators[increment]bir Redüktör, ancak her eylem için uygulandığı için ona ve actionOperator adını vermeyi tercih ederim. Durum sadece bir argümandır (ve dönüş değeri olarak bir başkası).

Reducer, ancak google arama sonuçlarının üstünde olmak için daha iyi bir kelimedir. Aynı zamanda Redux'a benzer.


0

Aşağıdaki bu kodda, akümülatörü eylemler olarak ve currentValue'u redux bağlamında bir durum olarak düşünmeniz yeterlidir. bu örnekle neden onu bir redüktör olarak adlandırdıklarını da öğreneceksiniz.

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// Main operation is 1 + 2 + 3 + 4 = 10
// but think of it as a stack like this: 

// | 2 | | 3 | | 4 | 
// |_1_| |_3_| |_6_| | 10 | => the 10 is in result

console.log(array1.reduce(reducer));
// expected output: 10

Azalt () yöntemi, dizinin her bir öğesi üzerinde bir düşürücü işlevi (sizin sağladığınız) çalıştırarak tek bir çıktı değeri sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.