GithubHelp home page GithubHelp logo

Comments (12)

dmitrig01 avatar dmitrig01 commented on April 20, 2024

I suppose I could make a mixin to eliminate some of the boilerplate, but this doesn't really solve the underlying problem: now, instead of storing state just in one place or another (in the component or store state), it's effectively stored in two places, which makes it a pretty terrible state mess.

from flux.

dmitrig01 avatar dmitrig01 commented on April 20, 2024

Digging a little deeper – sometimes parts of component state is not mirrored in stores – in the chat app, the message composer stores the message while it's being composed in local state, but when it's saved, it gets moved into a store. Maybe I'm not seeing something here – but it feels very inconsistent to me, and again, spreading state out over more places than necessary. Thoughts?

from flux.

fisherwebdev avatar fisherwebdev commented on April 20, 2024

Hi Dmitri,

We call them controller-views instead of ViewControllers because they are actual views, and not exactly controllers in the sense of MVC. They do pull data from the stores and pass that data to their children, however, and this is somewhat controller-like. Hence the name controller-view: a view that has controller-like functionality. If you compare this with ViewControllers in iOS, for example, you'll see that most people use that term to mean actual controllers that manage views, and do a whole lot more than what we are talking about here.

The use of setState() is a convention of React. You can certainly use forceUpdate() instead, but having the handle to this.state can be convenient. We are not really managing state in these controller-views. It's simply a convenient way to respond to the 'change' event and to get the data to the render method, allowing the render method to remain dedicated to rendering logic, instead of putting data fetching in there too. As long as you're not actually trying to manage state in the controller-view, there is nothing wrong with using this.state in this way. All the children below this controller-view will simply take the data in as props, and remain stateless.

When an individual component needs to manage it's own state (such as an input element, as you have noted) we do use this.state to do this. This is the one place in a Flux + React app where you do store state in a component that would otherwise be stateless. A significant difference here is that only this one component -- none of its children -- no other components -- need a reference to the component's state. Shared state should always be in the stores and pass through the component hierarchy as props. For more info on why input elements need to manage their own state, please see:

http://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html#what-components-should-have-state
and
http://facebook.github.io/react/docs/forms.html

I hope that helps!

from flux.

dmitrig01 avatar dmitrig01 commented on April 20, 2024

Yeah, the name makes total sense... I think I must have just forgotten – at least I got that the name had "controller" and "view" in it :-)

Very interesting on the distinction between shared state and individual state. Makes total sense. Maybe this is a silly question, but would it make sense for a component which manages its own state pass that state down to other components through their props, and listen via some kind of change listeners? In that case, why not have controller-views encapsulate the state entirely, without using stores?

Also interesting thought on using this.state as an effective shortcut to the store. I guess another part of my concern is mixing "store-state" with "component-state" in some components gets messy as well. I've managed this by having controller-views hold all their state in the store, even when it's not necessarily shared state. Does this make sense to do?

from flux.

briandipalma avatar briandipalma commented on April 20, 2024

Thanks for the answer @fisherwebdev

@dmitrig01 If you need to share state between react components flux recommends using stores, I see controller-views as views that layout other views and pass store data into them. Not as places to try and keep consistent models as you will be mingling concerns (the view and the domain model) if you were to do that.

State in stores doesn't have to be shared so I don't see an issue with storing everything in stores.

Your problem might be that your app isn't quite complex enough to require using flux, flux is something I would use for medium to high complexity applications/components.

from flux.

dmitrig01 avatar dmitrig01 commented on April 20, 2024

@fisherwebdev still curious on the best practice here – not sure about the best practice in terms of mixing "store-state" with individual/component-state in the component's state variable. Isn't it a little messy to do?

As a concrete example, I have a controller-view which has three pie charts which have the same keys but different values. When you hover over a slice on one, the same highlights on all three. The data contained by the charts would be considered "shared state", and resides in the store, but hover data seems to be state local to the controller-view. However, the component's state variable now contains aliased state from the store as well as actual/local state, which feels very messy. Does this make sense?

from flux.

briandipalma avatar briandipalma commented on April 20, 2024

Hover state does not seem local to the controller-view, that should be state that is local to the child view components, you hover over them not the view controller. The view controller just passes what is hover over into the child views when it's notified of a change by the store it listens to.

You shouldn't store hover state in the child views either then as they should have that value passed in to them from their parent view controller, all they do is call action creators which will eventually be handled by the store which then notifies the view controller which then...

from flux.

dmitrig01 avatar dmitrig01 commented on April 20, 2024

Interesting, this is what I got from what you were saying:

  1. Store the hovered state in a store
  2. Pie charts have an onHover callback
  3. The parent controller-view attaches an onHover function to its child pie charts that set data in the store (well, fires an action that sets data, but w/e)
  4. Have the parent controller-view pass in the store data to the when the store changes

Is that fair, or are you thinking something more along the lines of the pie chart components are actually their own controller-views? That feels really ugly to me.

In this instance, it seems somewhat pointless to store hover data in the store, as it's not shared state – it's only used in one instance of component, the controller-view

from flux.

fisherwebdev avatar fisherwebdev commented on April 20, 2024

@dmitrig01 Very sorry to have closed this on you. Please close when you feel you are understanding the Flux way of handling this.

We want to get rid of as much state from our React components as possible, and to move that state into the stores. So every time you find yourself keeping state in your components, ask yourself: "Can I move this state into the stores?" After thinking about it a bit, you'll find that this is possible, and it actually cleans up your code quite a bit. In your scenario, the hover state would be kept in the store as well. This might be something like the ChartStore's private _hightlightedPieSliceID variable.

The only exception to this rule is state that is 100% internal to the component, and even this is often something that can be put in stores. As I've said above, text input components are an example of this kind of component.

Controller-views are slightly different, however. The state they contain is often, as you say, a mirror of the stores' state. It also can be tailored to their specific needs, by providing more specific getter methods in the stores.

So in your scenario, I'm assuming you have something like this:

<PieChartControllerView>
  <PieChart />
  <PieChart />
  <PieChart />
</PieChartControllerView>

You could either get the entire state of the ChartStore, including the _highlightedPieSliceID (which can be null), or you could more specifically invoke ChartStore.getHightlightedPieSliceID().

Each PieChart would then receive the id as props, and know what to do with it.

from flux.

fisherwebdev avatar fisherwebdev commented on April 20, 2024

Is that fair, or are you thinking something more along the lines of the pie chart components are actually their own controller-views? That feels really ugly to me.

Yes, it sounds like you understand it correctly. No, they should not be their own controller-views.

In this instance, it seems somewhat pointless to store hover data in the store, as it's not shared state – it's only used in one instance of component, the controller-view

It's not pointless. It maintains the proper data flow, and as soon as you want to do something else with that hover state, like display related information in a table off to the side in a different column, you are looking at a significant refactoring. If you stick with the Flux pattern, you will have an easier time down the road. You will know where all the state is being maintained, how it gets updated, etc. Six months from now you will be able to open this app up again and know where everything lives. Putting the state in React components makes them less reusable, harder to reason about, more tightly coupled to each other and their specific context.

And it is in fact shared state -- each PieChart needs to know the currently hovered slice.

from flux.

fisherwebdev avatar fisherwebdev commented on April 20, 2024

Since we haven't continued this in a while, I'm assuming we're okay to close this one.

from flux.

dmitrig01 avatar dmitrig01 commented on April 20, 2024

yes – thanks

from flux.

Related Issues (20)

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.