New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to get action and state in store.subscribe? #580

Closed
antonmedv opened this Issue Aug 19, 2015 · 6 comments

Comments

7 participants
@antonmedv

antonmedv commented Aug 19, 2015

I want to update my view in listener:

store.subscribe(() => {
    updateView(store.getState()); // Some DOM api calls.
});

But if it possible to get last action what triggered state change, i can do some think like this:

store.subscribe(() => {
    switch (action.type) {
        case UPDATE_TITLE:
            updateTitle(store.getState().some.title); // Optimize rendering of view. Only one DOM api call.
        break;
        default:
            updateView(store.getState()); // Some DOM api calls.
    }
});

Is it possible to get action and state in store.subscribe?

@lapanoid

This comment has been minimized.

Show comment
Hide comment
@lapanoid

lapanoid Aug 19, 2015

I made some hacking around this https://github.com/lapanoid/redux-remote/blob/master/src/createSubscribeOnStateStore.js but I am sure it is not the best way to do this. Waiting forward for @gaearon comment.

lapanoid commented Aug 19, 2015

I made some hacking around this https://github.com/lapanoid/redux-remote/blob/master/src/createSubscribeOnStateStore.js but I am sure it is not the best way to do this. Waiting forward for @gaearon comment.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Aug 20, 2015

Collaborator

This is not something we want to include by default. It's a hack around the paradigm, so if you really need it, please do so at your own risk.

Non-React Way

The easiest way is to have a reducer that remembers just the last action:

function lastAction(state = null, action) {
  return action;
}

Then you can use store.getState().lastAction, assuming you did something like

import { combineReducers, createStore } from 'redux';

const rootReducer = combineReducers({
  someReducer,
  someOtherReducer,
  lastAction // <-- use it!
});

const store = createStore(rootReducer);

store.subscribe(() => {
  console.log(store.getState().lastAction);
});

Still, this is not quite how Redux app is supposed to work, as this breaks the consistency in rendering.

React Way

If you want to optimize a React component, optimizations described in “Advanced Performance” is what you should be after; not this.

As a last resort you can always do side effects in componentWillReceiveProps:

componentWillReceiveProps(nextProps) {
  if (this.props.title !== nextProps.title) {
    // If somehow we're sure we can actually be faster than React at this. (not likely)
    findDOMNode(this).doSomethingWith(nextProps.title);
  }
}
Collaborator

gaearon commented Aug 20, 2015

This is not something we want to include by default. It's a hack around the paradigm, so if you really need it, please do so at your own risk.

Non-React Way

The easiest way is to have a reducer that remembers just the last action:

function lastAction(state = null, action) {
  return action;
}

Then you can use store.getState().lastAction, assuming you did something like

import { combineReducers, createStore } from 'redux';

const rootReducer = combineReducers({
  someReducer,
  someOtherReducer,
  lastAction // <-- use it!
});

const store = createStore(rootReducer);

store.subscribe(() => {
  console.log(store.getState().lastAction);
});

Still, this is not quite how Redux app is supposed to work, as this breaks the consistency in rendering.

React Way

If you want to optimize a React component, optimizations described in “Advanced Performance” is what you should be after; not this.

As a last resort you can always do side effects in componentWillReceiveProps:

componentWillReceiveProps(nextProps) {
  if (this.props.title !== nextProps.title) {
    // If somehow we're sure we can actually be faster than React at this. (not likely)
    findDOMNode(this).doSomethingWith(nextProps.title);
  }
}
@MujtabaKably

This comment has been minimized.

Show comment
Hide comment
@MujtabaKably

MujtabaKably Apr 5, 2017

@gaearon
thanks for this awesome idea.

i agree it isnt best way to do it in react, but when using react + other-libs to develop an app that using redux as data sync it is the best way to do it

MujtabaKably commented Apr 5, 2017

@gaearon
thanks for this awesome idea.

i agree it isnt best way to do it in react, but when using react + other-libs to develop an app that using redux as data sync it is the best way to do it

@praburajan

This comment has been minimized.

Show comment
Hide comment
@praburajan

praburajan Apr 10, 2017

@gaearon @markerikson While this requirement is not needed for react and I do agree that its against the philosophy of writing code reacting to state changes rather than the event, it is important for other MVVM libraries to be able to use redux as the state management framework. Redux provides an awesome paradigm of writing all your business logic inside reducers which are pure functions, making testability, undo-redo very easy

praburajan commented Apr 10, 2017

@gaearon @markerikson While this requirement is not needed for react and I do agree that its against the philosophy of writing code reacting to state changes rather than the event, it is important for other MVVM libraries to be able to use redux as the state management framework. Redux provides an awesome paradigm of writing all your business logic inside reducers which are pure functions, making testability, undo-redo very easy

@matigda

This comment has been minimized.

Show comment
Hide comment
@matigda

matigda Oct 22, 2017

Can somebody please explain a little better the idea behind this?
Because IMO it would make a lot easier implementing some UI changes ( like lazy load reloading ) if the action is passed to the listener. Right now it is being fired on every state change ( that's ok ) but without any data provided you actually need to have some global variable to compare, as it is given in example above ( and that's not quite ok ). And without previous state or action being passed I can't really see the real usage of that method anyways. Judging from examples of that method usage it seems like there wasn't a clear idea how it can be used in real world application without violating any rule. So again... what exactly would be broken here if the action is passed to the listener?

matigda commented Oct 22, 2017

Can somebody please explain a little better the idea behind this?
Because IMO it would make a lot easier implementing some UI changes ( like lazy load reloading ) if the action is passed to the listener. Right now it is being fired on every state change ( that's ok ) but without any data provided you actually need to have some global variable to compare, as it is given in example above ( and that's not quite ok ). And without previous state or action being passed I can't really see the real usage of that method anyways. Judging from examples of that method usage it seems like there wasn't a clear idea how it can be used in real world application without violating any rule. So again... what exactly would be broken here if the action is passed to the listener?

@markerikson

This comment has been minimized.

Show comment
Hide comment
@markerikson

markerikson Oct 22, 2017

Contributor

@matigda : please see the linked issues for prior discussion, as well as the answer for this topic in the "Design Decisions" FAQ page.

Contributor

markerikson commented Oct 22, 2017

@matigda : please see the linked issues for prior discussion, as well as the answer for this topic in the "Design Decisions" FAQ page.

@reduxjs reduxjs locked as resolved and limited conversation to collaborators Jan 29, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.