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

Circular Dependencies between Stores #28

Closed
alxhill opened this Issue Aug 12, 2014 · 7 comments

Comments

Projects
None yet
6 participants
@alxhill

alxhill commented Aug 12, 2014

The current flux-chat example has a bug that means it doesn't update the lastMessage object in the ThreadStore. Trying to reconcile this by waiting for the MessageStore to complete (and then request the message list from the store) creates a circular dependency between MessageStore and ThreadStore.

I've ended up fixing this by doing the following:

  • Making a shared "DispatchTokens" object so one store can wait for another without requiring it as a dependency
  • Adding the full message object to payload.action (which otherwise only stores the text of the message)
  • Having the ThreadStore listen to the CREATE_MESSAGE action, wait for the MessageStore to complete, and updating lastMessage with the message object on the payload.

I'm curious if modifying the payload is the appropriate way of fixing this kind of issue. It seems like a viable option given that the waitFor guarantees that the message callback has completed, but does require a different way of storing dispatch tokens.

The other solution I had was to simply require MessageStore inside the ThreadStore callback instead of at the top of the file, but this felt a bit hacky.

Is mutating the payload considered an acceptable way of resolving this between stores, or is there a more 'Fluxy' way of doing things?

@justin808

This comment has been minimized.

Show comment
Hide comment
@justin808

justin808 Sep 6, 2014

Contributor

Here's my attempt to resolve this.

#48

Contributor

justin808 commented Sep 6, 2014

Here's my attempt to resolve this.

#48

@fisherwebdev

This comment has been minimized.

Show comment
Hide comment
@fisherwebdev

fisherwebdev Sep 29, 2014

Contributor

Well, I think all we need on on lastMessage is the date and whether or not it has been read. CREATE_MESSAGE could contain the date and anything created is obviously already read. This could be one way to go -- let the ThreadStore respond to CREATE_MESSAGE by creating a lastMessage object and mark it as read. CREATE_MESSAGE should be modified to contain the date. Not sure we need any other data in the lastMessage object.

Contributor

fisherwebdev commented Sep 29, 2014

Well, I think all we need on on lastMessage is the date and whether or not it has been read. CREATE_MESSAGE could contain the date and anything created is obviously already read. This could be one way to go -- let the ThreadStore respond to CREATE_MESSAGE by creating a lastMessage object and mark it as read. CREATE_MESSAGE should be modified to contain the date. Not sure we need any other data in the lastMessage object.

@fisherwebdev

This comment has been minimized.

Show comment
Hide comment
@fisherwebdev

fisherwebdev Sep 29, 2014

Contributor

The idea for a shared object for dispatcher tokens seemed interesting, but I don't think it will work -- you would still need to get the last message from the MessageStore, which would necessitate a require.

Contributor

fisherwebdev commented Sep 29, 2014

The idea for a shared object for dispatcher tokens seemed interesting, but I don't think it will work -- you would still need to get the last message from the MessageStore, which would necessitate a require.

@gsklee

This comment has been minimized.

Show comment
Hide comment
@gsklee

gsklee Mar 19, 2015

Is there any concrete advice now on how to handle the circular dependency problem between stores?

gsklee commented Mar 19, 2015

Is there any concrete advice now on how to handle the circular dependency problem between stores?

@tobice

This comment has been minimized.

Show comment
Hide comment
@tobice

tobice Jun 16, 2015

Hi, this issue is rather old but I'd also like to hear more on this. There are problems that contain circular dependencies stemming directly from their nature. There is no way around. How should we face them?

To give an example we can talk about, let's consider a game with two stores:

  • StateStore that contains the current game state, i. e. playing, paused, over and responds to actions like PAUSE or RESUME.
  • CharacterStore that contains the current position of the game character (i. e. coordinates) and responds to actions like MOVE_LEFT, MOVE_RIGHT etc.

When the game is paused, the CharacterStore shouldn't respond to any actions so it depends on the StateStore. But when the MOVE_LEFT action is dispatched and the game character falls into a trap (which is handled by the CharacterStore), the game state should change to over, so clearly the StateStore depends on the CharacterStore here.

The order in which the actions are handled is not a problem here. So I could solve this by instantiating both stores and exchanging references between them so they could both arbitrarily read from each other (something like the shared object for the dispatcher tokens, except it wouldn't be just the tokens, it would be the actual instances of stores). That would solve it... but is it right?

The other way would be to merge those stores into one. That would be logical. However, in a more complex example (with more stores representing the game situation) it could mean collapsing a huge app into a single store. There would not be much of Flux left.

Is there any strong opinion on this? Possibly my whole thinking is wrong. It's probably naive to expect Flux to work in every situation.

(I posted similar question on StackOverflow as well)

tobice commented Jun 16, 2015

Hi, this issue is rather old but I'd also like to hear more on this. There are problems that contain circular dependencies stemming directly from their nature. There is no way around. How should we face them?

To give an example we can talk about, let's consider a game with two stores:

  • StateStore that contains the current game state, i. e. playing, paused, over and responds to actions like PAUSE or RESUME.
  • CharacterStore that contains the current position of the game character (i. e. coordinates) and responds to actions like MOVE_LEFT, MOVE_RIGHT etc.

When the game is paused, the CharacterStore shouldn't respond to any actions so it depends on the StateStore. But when the MOVE_LEFT action is dispatched and the game character falls into a trap (which is handled by the CharacterStore), the game state should change to over, so clearly the StateStore depends on the CharacterStore here.

The order in which the actions are handled is not a problem here. So I could solve this by instantiating both stores and exchanging references between them so they could both arbitrarily read from each other (something like the shared object for the dispatcher tokens, except it wouldn't be just the tokens, it would be the actual instances of stores). That would solve it... but is it right?

The other way would be to merge those stores into one. That would be logical. However, in a more complex example (with more stores representing the game situation) it could mean collapsing a huge app into a single store. There would not be much of Flux left.

Is there any strong opinion on this? Possibly my whole thinking is wrong. It's probably naive to expect Flux to work in every situation.

(I posted similar question on StackOverflow as well)

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Aug 5, 2015

Thank you for reporting this issue and appreciate your patience. We've notified the core team for an update on this issue. We're looking for a response within the next 30 days or the issue may be closed.

ghost commented Aug 5, 2015

Thank you for reporting this issue and appreciate your patience. We've notified the core team for an update on this issue. We're looking for a response within the next 30 days or the issue may be closed.

@kyldvs kyldvs added the question label Nov 18, 2015

@kyldvs

This comment has been minimized.

Show comment
Hide comment
@kyldvs

kyldvs Dec 16, 2016

Contributor

@tobice sorry for the slow reply. I think what we typically do in this situation is allow both stores to reference each other in a circular manner, generally via an inline require.

// Not inline
const gameStatus = StatusStore.get();

// Inline
const gameStatus = require('StatusStore').get();

// Or move it to a function
function getStatusStore() {
  return require('StatusStore'); // or however else you get the reference
}
const gameStatus = getStatusStore().get();

Going to close this out as there seems to have been sufficient discussion and the chat example was also removed. If there are still specific questions or action items feel free to reopen or file a different issue.

Contributor

kyldvs commented Dec 16, 2016

@tobice sorry for the slow reply. I think what we typically do in this situation is allow both stores to reference each other in a circular manner, generally via an inline require.

// Not inline
const gameStatus = StatusStore.get();

// Inline
const gameStatus = require('StatusStore').get();

// Or move it to a function
function getStatusStore() {
  return require('StatusStore'); // or however else you get the reference
}
const gameStatus = getStatusStore().get();

Going to close this out as there seems to have been sufficient discussion and the chat example was also removed. If there are still specific questions or action items feel free to reopen or file a different issue.

@kyldvs kyldvs closed this Dec 16, 2016

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