Coder Social home page Coder Social logo

kutlugsahin / redux-saga-callback Goto Github PK

View Code? Open in Web Editor NEW
21.0 3.0 2.0 374 KB

redux-saga helper functions to await dispatched actions

License: MIT License

JavaScript 52.83% TypeScript 47.17%
redux redux-saga higher-order-functions yield putwait

redux-saga-callback's Introduction

redux-saga-callback

In a normal flow of a redux-saga application there might be some cases that you want get notified when a saga triggered by a dispatched action is completed. The purpose of this library is to provide some helper functions to achieve that functionalities.

Install

npm i redux-saga-callback

Usage

import { putWait, withCallback } from 'redux-saga-callback';

Wrap your saga generator with withCallback

takeEvery('FETCH_USERS', withCallback(fetchUsers));

Defined callback in your action if you need

dispatch({type: 'FETCH_USERS', onComplete: ({error, cancelled, data}) => {

}})

In saga you can wait for it (no callback definition is needed with putWait)

const users = yield putWait({type: 'FETCH_USERS'});

API

withCallback

This is a higer order saga which will call the onComplete callback property of the action if defined.

onComplete

  • error: error which is thrown by the saga
  • cancelled: Will be true if the saga is cancelled
  • data: the data returned by the saga
function onComplete({ error, cancelled, data }) {
    /* handle callback */
}
function* fetchUsers() {
    const users = yield fetch('/users');

    // put users to store
    yield put(putUsers(users));

    // returned value will be passed to onComplete function as parameter
    // Exceptions will be handled by the withCallback and will also be passed to onComplete
    return users;
}

export function*(){
    yield all([
        takeEvery('FETCH_USERS', withCallback(fetchUsers))
    ])
}

// userSaga.js
// Component to list users
export const Users = () => {
    const [isLoading, setIsLoading] = useState(true);
    const [users, setUsers] = useState([]);

    const dispatch = useDispatch();

    function onUsersFetchCompleted({ error, cancelled, data }) {
        setIsLoading(false);
        if (!err && !cancelled) {
            setUsers(data);
        }
    }

    useEffect(() => {
        dispatch({
            type: 'FETCH_USERS',
            onComplete: onUsersFetchCompleted,
        });
    }, []);

    return isLoading ? (
        'Loading'
    ) : (
        <ul>
            {users.map(user => (
                <li>{user.name}</li>
            ))}
        </ul>
    );
};

// Users.jsx

putWait

An effect that dispatches the action (same as put effect) which you can yield and wait for that saga to be completed only if the saga is created using withCallback higher order saga

Example

function* loadCurrentUserData() {
    const currentUserId = getCurrentUserId();

    let users = yield select(state => state.users);

    if(!users) {
        // waits until fetchUsers saga is completed
        // fetchUser saga is defined in userSaga.js above
        users = yield putWait({type: 'FETCH_USERS'});
    }

    return users.find(p => p.id === currentUserId);
}

export function*(){
    yield all([
        takeEvery('LOAD_CURRENT_USER', fetchUsers)
    ])
}

// userData.js

redux-saga-callback's People

Contributors

dependabot[bot] avatar kutlugsahin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

redux-saga-callback's Issues

Actions must be plain objects. Use custom middleware for async actions.

I'm a little stuck. I recieve the callback to the action creator but unable to send that to the intial call function at Login. Any help would be appreciated

Login

handleOnLogin = async (values, actions) => {
    const { email, password } = values;
    try {
      const response = await this.props.signIn({ email, password });
      if (response.authentication) {
        this.props.navigation.navigate("Home");
      }
  };

Actions

export const signIn = ({ email, password }) => {
  reduxStore.store.dispatch({
    type: Actions.SIGN_IN_REQUEST,
    payload: {
      email: _.trim(email),
      password: _.trim(password)
    },
    onComplete: ({ error, cancelled, data }) => {
      console.log("ACTIONS", { error, cancelled, data });
      return data
    }
  });
};

Sagas

const signIn = function* signIn({ payload }) {
  try {
    const { email, password } = payload;
    const response = yield call(API.signIn, { email, password });
    // yield putWait({ type: Actions.SIGN_IN_SUCCESS, payload: response });
    return { response, authentication: true };
  } catch (error) {
    // yield putWait({ type: Actions.SIGN_IN_FAIL, error });
    return { error, authentication: false };
  }
};

usage with takeLatest/takeLeading

First of all thanks for this library.
But looks like putWait won't work for

  • takeLatest(actiontype, withCallback(... ->
  • takeLeading(actiontype, withCallback(... ->

take latest example

function* fetchUsers() {
    const users = yield fetch('/users');

    // put users to store
    yield put(putUsers(users));

    // returned value will be passed to onComplete function as parameter
    // Exceptions will be handled by the withCallback and will also be passed to onComplete
    return users;
}

export function*(){
    yield all([
        takeLatest('FETCH_USERS', withCallback(fetchUsers))
    ])
}

function* sample() {
    yield fork(function* () {
         yield putWait(fetchUsers()); // will be completed before users loaded because first handler is cancelled
         const users = yield select(getUsers);  // here users will be null
    });

    yield fork(function* () {
         yield putWait(fetchUsers());
         const users = yield select(getUsers); 
    });
}

takeLeading example

....


export function*(){
    yield all([
        takeLeading('FETCH_USERS', withCallback(fetchUsers))
    ])
}

function* sample() {
    yield fork(function* () {
         yield putWait(fetchUsers()); 
         const users = yield select(getUsers);  
    });

    yield fork(function* () {
        // this putWait never completes because takeLeading ignore second action while first one is processing
         yield putWait(fetchUsers());  
         const users = yield select(getUsers); 
    });
}

Maybe you have any idea how to get working it in these cases. Thanks in advance!

Does redux-saga-callback swallow actions?

Firstly, thanks for this code. It's in TypeScript, which is a big win, and provides a valuable approach on the topic of saga composition.

In the case where I want the dispatched action to actually be processed by the reducers, will that happen?

My issue is that when I yield call(effect, action()), the action doesn't reach my redux store. In some cases, that's an issue. I could split my actions into saga triggering events and redux reducer actions, but that seems a bit convoluted, error prone, etc. I guess to work around this would require a redux middleware... ๐Ÿค”

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.