-
Notifications
You must be signed in to change notification settings - Fork 7
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
Wc 70 textinput pure component #246
Conversation
src/forms/TextInput.jsx
Outdated
this.onChange = this.onChange.bind(this); | ||
} | ||
|
||
onChange(e) { | ||
this.setState({ value: e.target.value }); | ||
if (this.props.onChange) { | ||
this.props.onChange(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you attached this directly to the onChange prop of the input, you could really trim down a lot of the code in this component:
<input onChange={this.props.onChange} ... />
You'd be able to delete the constructor
and onChange
methods altogether while keeping the same functionality. You could then even go one step further and define this as a stateless functional component instead of a class if you wanted (no need to worry about this
or lifecycle methods):
class TextInput extends React.PureComponent {
render() {
const { /* destructure props */ } = this.props;
return <input ... />
}
}
// vs
function TextInput({/* destructure props */}) {
return <input ... />
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm ok. Well what do we prefer? PureComponent
vs stateless functional component? What are the benefits?
@eilinora should we go for the latter instead of a PureComponent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @mikespencer we should be trying to go for stateless functional components as much as possible. Especially at the MWC level. I think my only concern is how this change would interact if we wanted this component to work with redux forms. @mikespencer any concerns there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think my only concern is how this change would interact if we wanted this component to work with redux forms. @mikespencer any concerns there?
Ah right - so this won't work as is with redux-form. Redux-form passes in props in a specific way to the rendered component. I like the idea of having this component being purely presentational though with no ties to a specific library, like redux-form.
One way I'd love to see this work would be to wrap this in another component that is meant for consumption by redux-form, roughly something like:
import TextInput from 'meetup-web-components';
const ReduxFormTextInput = function ReduxFormTextInput(props) {
const translatedProps = {
// convert the props that redux-form passes into this component into something that TextInput understands
}
return <TextInput {...translatedProps} />;
}
That way, this TextInput can be used in different situations purely for presentation and is totally decoupled from redux-form
I made this a functional component but the most basic tests (eg it exists) are even failing. Stroybook looks good. Any ideas how the test needs to change @mikespencer |
Tests need to be changed since this is a functional component, and TestUtils.renderIntoDocument returns null for these tyes of components My fix is to create a |
src/forms/TextInput.jsx
Outdated
@@ -5,79 +5,62 @@ import cx from 'classnames'; | |||
/** | |||
* @module TextInput | |||
*/ | |||
class TextInput extends React.Component { | |||
function TextInput(props) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can i be obnoxious and ask this to be written es6'y?
const TextInput = props => { ... };
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
happy to oblige
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing to note with doing it this way (anonymous function) is that it can be trickier to figure out what the problem is if you are looking at an error's call stack. Personally, I prefer to reference airbnb's style guide where they recommend explicitly naming the function in these sort of situations. Not a major thing, but something to be aware of
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, yeah we've been doing it the es6 way as we've been migrating to stateless. I see the style guide says boo to it. I vote for the es6, but I'll defer to the collective on which way we go. 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend using an arrow function + static .displayName
property or a named function, but not a 'bare' arrow function without a name.
src/forms/textInput.test.jsx
Outdated
@@ -10,6 +11,16 @@ describe('TextInput', function() { | |||
MAX_LEN = '20', | |||
ERROR_TEXT = 'Too wimpy.'; | |||
|
|||
// Note: since TextInput is a functional component | |||
// we need to wrap it in a stateful component to use TestUtils effectively | |||
const TestWrapper = createReactClass({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be good to make this a utility as we move other MWC components to stateless. i suggest in testUtils
@@ -21,12 +32,14 @@ describe('TextInput', function() { | |||
required: true, | |||
}; | |||
textInputComponent = TestUtils.renderIntoDocument( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A renderComponent function might also be helpful for future updates... e.g. https://github.com/meetup/mup-web/blob/master/src/components/events/eventTimeDisplay.test.jsx#L19
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since I won't be using that in these tests I'm reluctant to add it. I will when I do though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only change i'm gonna say is a blocker is my obnoxious es6 comment https://github.com/meetup/meetup-web-components/pull/246/files#r126474675. Everything else is nice to haves.
I just realised I left a comment in a collapsed comment, so in case it gets missed I'm just going to paste it here:
Ah right - so this won't work as is with redux-form. Redux-form passes in props in a specific way to the rendered component. I like the idea of having this component being purely presentational though with no ties to a specific library, like redux-form. One way I'd love to see this work would be to wrap this in another component that is meant for consumption by redux-form, roughly something like: import TextInput from 'meetup-web-components';
const ReduxFormTextInput = function ReduxFormTextInput(props) {
const translatedProps = {
// convert the props that redux-form passes into this component into something that TextInput understands
}
return <TextInput {...translatedProps} />;
} That way, this TextInput can be used in different situations purely for presentation and is totally decoupled from redux-form EDIT: We could even leverage |
ok @mikespencer, so the if this review is good to go, I'll merge - just let me know! |
Yeah I think that one could be debated - if the goal of meetup-web-components is to be purely presentational, then I'd say it's probably best not to have components coupled to redux-form inside here, since it assumes the consuming application is using redux-form. Although, if the majority of the repos consuming this meetup-web-components do use redux-form, then having a redux-form input component in here could be an easy easy way to share between applications. I guess an ideal approach would be to have another package for meetup-redux-form-components that basically wrap meetup-web-components to make them compatible with redux-form, but that's just my opinion! Either way, I think all of the above are out of the scope of this PR, so I'm 👍 with this. |
Oh that brings up a good point, there should be a |
// Note: functional components need to be | ||
// wrapped it in a stateful component to use TestUtils effectively | ||
export const TestWrapper = createReactClass({ | ||
render: function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in general the preferred solution would be to use enzyme instead of TestUtils.renderIntoDocument
in these cases - I think it's fine to add this helper for 'legacy' code, but I'd like to see a @deprecated
code comment and (ideally) a console.warn('Using deprecated TestWrapper for TestUtils.renderIntoDocument - covert test to use enzyme')
as a loud flag about the tech debt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok so - how do we start using enzyme? we can do this in a separate branch and I can make a ticket for that. if you want I can add the deprecated comment but I dont know if that really helps?... as of this tool set and library this code is valid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure no problem. steve and I are on the team. I can do some reading - I just would like to do this upgrade/changes in a separate ticket to make sure it corrects this problem. I'm also checking in with adam to make sure he knows.
merging, stay tuned for enzyme |
Related issues
Fixes https://meetup.atlassian.net/browse/WC-70
related to https://meetup.atlassian.net/browse/WC-69
Description
Lets make our inputs and form fields PureComponents. This way they will play well with Redux forms in the app as well.
Screenshots (if applicable)