Skip to content
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

[Proposal] Stateless Material-UI #2784

Closed
2 of 6 tasks
alitaheri opened this issue Jan 4, 2016 · 22 comments
Closed
2 of 6 tasks

[Proposal] Stateless Material-UI #2784

alitaheri opened this issue Jan 4, 2016 · 22 comments
Labels
component: snackbar This is the name of the generic UI component, not the React module! discussion umbrella For grouping multiple issues to provide a holistic view

Comments

@alitaheri
Copy link
Member

alitaheri commented Jan 4, 2016

After seeing a huge number of regressions and bugs introduced only because there are 2 sources of truth for most components (state and prop) I have come to the conclusion that state is bad for business.

The Problem

Take a look at all the bugs. I can argue that more than half of them is caused by the complexity of internal logic of the components. And the biggest reason is keeping the state up-to-date with props.

The Solution

No more support for uncontrolled behavior!

How about forms?

  1. A simple wrapper can do the trick:
<Stateful ref='input' defaultValue={/*...*/}>
  <CheckBox/>
</Stateful>

you can then call imperative methods on this.refs.input. or handle the on change. This will require standard callback signatures which is a must even without this.
2. Third party projects like Fromsy can solve this issue
3. HOC on user-side. I don't think it is that hard to implement anyway.

Roamap

  • Remove imperative methods from the library (except for focus, damn focus)
  • Do something about theme handling to remove all the redundant codes
  • Standardize the API, i.e. value + onChange(event, value) [debatable] and no more!
  • Implement a wrapper that consumes the standard API to easily support form actions
  • Brag about the awesomeness of controlled components
  • Remove support for uncontrolled components

@oliviertassinari @mbrookes @newoga I would like to hear your insight on this. Thanks 👍 👍

@alitaheri alitaheri added Core discussion umbrella For grouping multiple issues to provide a holistic view labels Jan 4, 2016
@mbrookes
Copy link
Member

mbrookes commented Jan 4, 2016

Not that formsy-material-ui is particularly complex as most of the hard work is done by formsy-react (and there is plenty of room for improvement - HOC not mixin, ES6 classes, ES6 modules), but from my perspective, if the material-ui form component API was standardised, it would have made implementation much simpler still.

Across the form components, there are at least three variations of the onChange callback parameter order / content, and a mix of whether components can be uncontrolled, or should be controlled - and this isn't stable across releases of material-ui.

So, I am supportive of the idea, but I'm conscious that it would be a breaking change. If it's going to happen, then sooner is better than later I think.

@alitaheri
Copy link
Member Author

then sooner is better than later I think.

I love the sound of that. The sooner it happens I'll have less code to worry about. But if we ease into it everyone will have time to slowly adept and make smaller changes per release.

I you ask me I'm all in for sooner. But i'm not the only user of this library ( ^_^ )

@oliviertassinari
Copy link
Member

But if we ease into it everyone will have time to slowly adept and make smaller changes per release.

Yeah, let's wait a bit 😁.
In the meantime, I think that we have important stuffs to take care of that shouldn't require breaking changes 🎉

  • the should component update
  • the inline style
  • the theming
  • ES6 class definition of component
  • versioning the documentation

@oliviertassinari
Copy link
Member

I agree with you, the simpler our component are, the best it's. Going in this direction sounds like a good idea 👍.

@newoga
Copy link
Contributor

newoga commented Jan 4, 2016

I'm very much in agreement with this direction (probably not much of a surprise 😄). I think it makes a lot of sense to externalize the state and allow the developer to decide where they want state stored (ie. a basic stateful wrapper component or something like redux). I'd very much like to write some tooling to better integrate material-ui with redux in some of my personal projects and this would certainly help. 👍

@oliviertassinari
Copy link
Member

I have just discovered https://github.com/acdlite/recompose. That's preaty interesting!
They have:

  • a withContext()
  • a pure()

That could make our life easier 😍.
Regarding the performances of HOC: https://github.com/acdlite/recompose/blob/master/docs/performance.md

What about migrating with this and radium 😁?

@newoga
Copy link
Contributor

newoga commented Jan 5, 2016

@oliviertassinari Yeah that's a cool toolset. I ran into it earlier and thought it might be useful too. Also that post on performance is very interesting!

@alitaheri
Copy link
Member Author

I really like how Recompose addresses such issues 👍 👍

But... We still have 2 concerns with Recompose:

  1. They are all function components, you can't ref 'em, for apps it's ok, but for libs that's scary to users.
  2. Imperative methods are not forwarded. sure we wanna remove all the imperative methods. but focus guys!

the should component update
the inline style
the theming
ES6 class definition of component
versioning the documentation

Yeah I think code quality matters too 👍 👍 I want to address the theme for now, We will clean up a whole lot of components with this. I don't think I can continue with my previous huge PR with that huge es-lint rule though 😁.

@oliviertassinari So have we decided on Radium? Do you think how they traverse the tree can impact performance that badly? 😁

P.S. We can still consider inheritance. I'll continue my work so we can see how it would turn out 😁

@oliviertassinari
Copy link
Member

  1. They are all function components, you can't ref 'em, for apps it's ok, but for libs that's scary to users.

That's not true, for performance reason, they are using a class under the hood for soom recompose function. That's not yet documented.
Plus, they expose a toClass:

Converts a function component to a class component, e.g. so it can be givena ref.
Returns class components as is.

sure we wanna remove all the imperative methods.

Yes, that would be awesome.

but focus guys!

I guess we can use

this.refs.input.refs.input.focus();

instead of

this.refs.input.focus();

@oliviertassinari So have we decided on Radium? Do you think how they traverse the tree can impact performance that badly? 😁

Well, if we split up our component and implement should component update correctly, that should be ok. I'm considering Radium since it's maintained by a guy working at facebook and it's popular.

@alitaheri
Copy link
Member Author

Alright, I'll study Recompose a bit more.

And I agree with Radium too. It's got good stuff 😁

@oliviertassinari
Copy link
Member

By the way, radium and react-look are using the HOC like approach. So, even if we use the inheritance, we will have to deal with those issues.

@alitaheri
Copy link
Member Author

@oliviertassinari Yeah I guess -_- This is getting hard 😫 I have to give it a lot of thought. @newoga You think about this too 😁

@newoga
Copy link
Contributor

newoga commented Jan 6, 2016

@alitaheri @oliviertassinari Will do. I starting writing a long response earlier before deciding it was too long and most likely wasn't worth the read 😆. I'm certainly continuing to give this thought. Like we said before, I believe if we continue to refactor/clean up code in the more obvious areas, things will become clearer and we'll have a better "playground" to experiment with these different approaches and libraries.

I have some more specific thoughts maybe in which the order we can start doing some of the activities on the roadmap. I'll jot some ideas down later and share for feedback.

@alitaheri
Copy link
Member Author

@newoga Sounds good to me, I agree that we should focus on the quality of the code and get rid of all the magic in the code before we can actually work on something new 👍 👍

@mbrookes
Copy link
Member

mbrookes commented Feb 1, 2016

Related: #2957

@Kosta-Github
Copy link
Contributor

With the move to a (more) stateless implementation the react alternative preact might be usable, which would bring in a very low bundle footprint of only 3kb: preact.

@newoga
Copy link
Contributor

newoga commented Feb 12, 2016

With the move to a (more) stateless implementation the react alternative preact might be usable, which would bring in a very low bundle footprint of only 3kb: preact.

@Kosta-Github That's an interesting point. Moving to functional components that return JSX technically opens up the possibility for material-ui to be used with frameworks outside of React that use JSX, like preact. 👍

@nikgraf
Copy link
Contributor

nikgraf commented Feb 21, 2016

I really like the idea of separating between stateless & stateful component! ❤️

  1. How do you imagine the directory structure? We could split it the directories pure & stateful in the same repository/package.
  2. Some components have very complex state management. Especially when keyboard navigation is managed (see Datepicker Code). Making them pure would probably require to introduce new function to get to a sensible way of managing what was internal state before e.g. _addSelectedDays in DatePicker should probably become a public callback. The more I think about it, the more I like it. What are your thoughts?
  3. I would love to see the API normalised as @alitaheri suggested. I'm wondering what you think about replacing onChange with something else?
    Explanation: onChange is native to React and is called with SynteticEvent that contains the value inside the target. By having onChange(value) or onChange(event, value) we break with the signature of React's onChange API and newcomers need to learn that. It's not a huge big of a deal, but consistent APIs improve the developer experience long term. Why shouldn't we do onChange(event): because we would need to create SynteticEvents while in most cases people only want the value. I suggest onUpdate({ value: <here the real value> }) or also can be onModify or onValueChange. Having an object with value inside allows us to extend it without breaking the API in the future.

@alitaheri
Copy link
Member Author

@nikgraf Thanks for taking part in the discussion 👍 The more brain power we have the better the decision we make 😁

  1. I was thinking more like material-ui/Snackbar and material-ui/Snackbar/stateful. But that's open to discussion we might have more versions than we think O.o
  2. I'm working on a library to keep all controlled props inside a wrapper that will work like this:

    createWrapper(['value', 'open', 'etc'])(Component) it will create a class with onValueChange, onOpenChange, onEtcChange, defaultValue, defaultOpen, defaultEtc props and clearValue, setValue, getValue, ... methods. That way all we need to to is write a file with a wrapper in it 😁
  3. I'm thinking even a more standard manner. like: onValueChange as I mentioned above.

That wasn't the original reason. it's for integration with the Wrapper. we still pass the event. it won't break their previous knowledge. the thing about passing an object is that it's very uncommon and a bit hard to document and keep track of, but it's something workth discussing 👍 Thanks fo your awesome feedback 😄

@yanickrochon
Copy link

Reading the roadmap, being farily new to React and all, I found this issue and wondered why this.refs was being recommended? Isn't this ignoring React's own warning about Don't Overuse Refs?

@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 24, 2016

why this.refs was being recommended?

@yanickrochon This thread is almost 1-year-old. Things have changed in the ecosystem since then.
That's why.
One interesting approach is to allow parent having access to the children is by adding a rootRef callback property, E.g.

@oliviertassinari oliviertassinari added the component: snackbar This is the name of the generic UI component, not the React module! label Dec 18, 2016
@oliviertassinari
Copy link
Member

oliviertassinari commented Jul 8, 2017

I have come to the conclusion that state is bad for business.

@alitaheri I 100% agree, we have removed as much as state as possible in the components migrated to the v1-alpha branch. I think that we can close it, we have learned from our mistakes :).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: snackbar This is the name of the generic UI component, not the React module! discussion umbrella For grouping multiple issues to provide a holistic view
Projects
None yet
Development

No branches or pull requests

7 participants