Redux-saga: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
Line 165: Line 165:
}
}
</syntaxhighlight>
</syntaxhighlight>
= Channels =
== Action Channel ==
Buffer actions to be processed one at a time<br />
<syntaxhighlight lang="javascript">
function* updateSaga() {
    let chan = yield actionChannel("UPDATE");
    while(true)
    {
        yield effects.take(chan);
        conole.info("Update logged.");
        yield delay(1000);
    }
}
</syntaxhighlight>
With an action channel no events are lost. Whereas if the take was yield.take("UPDATE"), only events outside of the delay would be processed.
== General Channel ==
Communicate between to sagas<br />
<syntaxhighlight lang="javascript">
function* saga() {
    let chan = yield channel();
    function* handleRequest(chan) {
        while(true)
        {
            let payload = yield effects.take(chan);
            console.info("Got payload.");
            yield delay(1000);
        }
    }
    yield effects.fork(handleRequest, chan);
    yield effects.fork(handleRequest, chan);
    yield effects.put(chan, {payload:42} );
    yield effects.put(chan, {payload:42} );
    yield effects.put(chan, {payload:42} );
}
</syntaxhighlight>
The first two request as logged and then the third on looping around.
== Event Channel ==
Connects app to outside event sources e.g. web sockets<br />

Revision as of 05:19, 29 May 2020

About

  • Manages side-effects
  • Depends on ES6 and Yield
  • Consumes and emits actions
  • Works without redux

Generator functions

The functions does not execute. It waits until .next() is called and progresses through the function breaking after each yield

var delayGenerator = function* () {
   let data1 = yield delay(1000,1);
   console.info("Step 1");
   let data2 = yield delay(1000,2);
   console.info("Step 2");
   let data3 = yield delay(1000,3);
   console.info("Step 3");
}

var obj = delayGenerator()
obj.next() 
// Console Step 1
obj.next() 
// Console Step 2
obj.next() 
// Console Step 3

Using co

co runs the generator and the then holds the result.

var wrapped = co.wrap(delayGenerator);
wrapped().then( v=>console.log("Got a value:", v));
// Console Step 1
// Console Step 2
// Console Step 3
// Got a value: 6

Effects

Take

Take waits for an event to occur in the generator

var mySaga = function* () {
   console.info("Start");
   const state = yield effect.take("SET_STATE");
   console.info("Got State", state);
}

So dispatch can make it conclude

dispatch({state:"SET_STATE"});

Put

Put puts an action in the store

var putSaga = function* () {
    yield effect.put({type:"SET_STATE", value:42});
}

So

run(putSaga)

Will result in mySaga completing

fork

fork forks a process, i.e. it is the child of the original thread. e.g.

export function* loadItemDetails(item) {
    console.info("item?",item);
    const { id } = item;
    const response = yield fetch(`http://localhost:8081/items/${id}`)
    const data = yield response.json();
    const info = data[0];
    yield put(setItemDetails(info));
}

export function* itemDetailsSaga() {
    const { items } = yield take("SET_CART_ITEMS");
    yield all (items.map( item=>fork(loadItemDetails,item)));
}

Each item is updated on a new child thread. Fork means than the effect cancel can be used to stop the thread.

spawn

spawn is like fork but also like the unix function spawn. It starts a new unrelated thread to perform its work can cannot be cancelled.

TakeEvery

TakeEvery waits on an event and forks a new process.

let process = function* () {
    let timesLooped = 0;
    while(true) {
        console.info(`Looped ${timesLooped++} times`);
        yield delay(500);
    } 
}

let saga = function*() {
    yield effects.takeLatest("START_PROCESS", process);
}

run(saga)

dispatch( {type:"START PROCESS"});
// Looped 1 times
// Looped 2 times
// Looped 3 times
dispatch( {type:"START PROCESS"});
// Looped 1 times
// Looped 2 times

TakeLatest

TakeLatest waits on an event and forks until a new event. The current is cancelled and a new fork is started.

let process = function* () {
    let timesLooped = 0;
    while(true) {
        console.info(`Looped ${timesLooped++} times`);
        yield delay(500);
    } 
}

let saga = function*() {
    yield effects.takeLatest("START_PROCESS", process);
}

run(saga)

dispatch( {type:"START PROCESS"});
// Looped 1 times
// Looped 2 times
// Looped 3 times
dispatch( {type:"START PROCESS"});
// Looped 1 times
// Looped 2 times

All

This allows you to wait on a group of things e.g.

export function* itemPriceSaga() {
    const [{user},{items}] = yield all([
        take(SET_CURRENT_USER),
        take(SET_CART_ITEMS)
    ]);
    yield all (items.map(item=>call(fetchItemPrice, item.id, user.country)));
}

Channels

Action Channel

Buffer actions to be processed one at a time

function* updateSaga() {
    let chan = yield actionChannel("UPDATE");
    while(true)
    {
        yield effects.take(chan);
        conole.info("Update logged.");
        yield delay(1000);
    }
}

With an action channel no events are lost. Whereas if the take was yield.take("UPDATE"), only events outside of the delay would be processed.

General Channel

Communicate between to sagas

function* saga() {

    let chan = yield channel();

    function* handleRequest(chan) {
        while(true)
        {
            let payload = yield effects.take(chan);
            console.info("Got payload.");
            yield delay(1000);
        }
    }

    yield effects.fork(handleRequest, chan);
    yield effects.fork(handleRequest, chan);

    yield effects.put(chan, {payload:42} );
    yield effects.put(chan, {payload:42} );
    yield effects.put(chan, {payload:42} );
}

The first two request as logged and then the third on looping around.

Event Channel

Connects app to outside event sources e.g. web sockets