Conversation
Since the components are already stateless, we can transform them into functions without much troubles. This is likely to enhance Reps performance which are a known bottleneck for some tools (e.g. the Console).
The main failure was the one testing that the Rep component was picking up the expected Rep (Grip, TextNode, ...) component given a specific object. The test is modified to use the `getRep` function, that the Rep (from rep.js) calls to render the expected component, since the shallow render would only gives us the type returned by the function, and not the function name.
|
Let's put the review on hold for now, the PR isn't really readable TODO:
|
|
So I set up a quick test with components as ES6 classes on a handful of Reps. For now I'm going to stick with functions, and we'll evaluate introducing stateful components when creating or modifying Reps. I will now clean up my PR and ask for review when everything is okay. |
|
@juliandescottes is so brave he says he can handle it as is. I'll amend the commit message to better reflect what was done (switch to functional component, creation of a safeObjectLink helper, removal of unused methods, better consistency across reps) |
juliandescottes
left a comment
There was a problem hiding this comment.
Few nits, but looks great! I tried to be as thorough as possible, I might have missed a few things but I think this is good to go.
Any migration needed in mc in your opinion? (thinking about redundant calls to createFactory?)
| return []; | ||
| } | ||
|
|
||
| function safeObjectLink(props, config, ...children) { |
There was a problem hiding this comment.
Thanks for moving this to a dedicated util!
Let's add a JSDoc
| } | ||
|
|
||
| module.exports = { | ||
| createFactories, |
There was a problem hiding this comment.
Not to be changed here, but createFactories is no longer used inside of the reps project, only in mc. Maybe we should move it from reps to a shared mc util?
There was a problem hiding this comment.
Yes, I agree.
I can still remove it here and file a bug on m-c to move it to a shared util and do the refactor where the one from reps is used for now.
How do you think we should operate ?
There was a problem hiding this comment.
I would say :
- create a bug in mc to duplicate createFactories from reps in a mc util and use it everywhere
- update the image in circle after bug has been resolved
- nuke createFactories here
There was a problem hiding this comment.
| }); | ||
| function StringRep(props) { | ||
| let { | ||
| object: text, |
There was a problem hiding this comment.
let's add cropLimit since we're using destructuring for this one now.
| * and the max number of rendered items depends on the current mode. | ||
| */ | ||
| let ArrayRep = React.createClass({ | ||
| displayName: "ArrayRep", |
There was a problem hiding this comment.
This comment applies to all the migrated components here.
I've been trying to check the behavior of the new functional components when we provide them with invalid/missing props, to check that the propTypes validation was still effective.
For some reason I can't get it to work. Adding a new required propType does not trigger any warning message (I was of course using a dev version of react and making sure that I was calling the rep I modified).
So just as a fair warning, we're probably losing proptypes validation here. I guess it's still good for documentation and that's the main reason we are using it.
Still this "should" work, can't find the reason why it's not doing anything.
There was a problem hiding this comment.
I will investigate that.
Maybe what I did in wrapRender isn't enough, I'll check.
It would be nice to still have these warnings
There was a problem hiding this comment.
Okay I found it.
I think react does very little with our functional component, and that might include propTypes validation.
If instead of directly calling my rep StringRep(props) I do React.createElement(StringRep, props) I do have the warning messages.
Now I must figure out if doing that will impact the performance of Reps.
If it does, I think we might give Flow a try to replace propTypes maybe ?
There was a problem hiding this comment.
Ah great to know where this is coming from at least. Totally agree with your proposal, let's check if there is a performance impact. If there is one, yes flow will be an option.
There was a problem hiding this comment.
So I tested it with my test case of 1000 reps (launched 10 times to get an average) :
React.createClass : ~ 3500ms
Functions + React.createElement: ~2200ms
Functions : ~1600ms
Function is definitely faster and I don't think the benefit we get from doing React.createElement (having propTypes warnings) justify the loss of performance.
There was a problem hiding this comment.
Thanks for testing! I agree it's not worth the performance impact.
src/reps/object.js
Outdated
| * Get an array of components representing the properties of the object | ||
| * | ||
| * @param {Object} object | ||
| * @param {Boolean} truncate true if the object will be truncated. |
There was a problem hiding this comment.
I think it's more accurate to say that truncate is true if the object has been truncated (and maybe rename to truncated ?). We actually truncate when building "interestingObject" and depending on that, we decide to use a comma or not for the last item.
src/reps/object.js
Outdated
| return propsArray; | ||
| } | ||
| function propIterator(props, object, max) { | ||
| let isInterestingProp = (t, value) => { |
There was a problem hiding this comment.
Maybe use an explicit argument name "type" instead of t (I know this is not really changed by your commit, but since you modified a bit the way we build the props arrays here, I had to read it carefully and the "t"s were pretty annoying :) )
|
Review updated with your feedback @juliandescottes |
Moving from classes to functions showed a solid 50-60% improvement in my test case (1000 Object reps).
There isn't much drawbacks of doing this since all the component were already stateless.
The only things I had to change were the tests that make sure the root
Repcomponent chose the correct component given a specific grip. The solution I came with is to directly test thegetRepfunction thatRepcalls.I wonder if this is enough though, because of course at some point
Repcould do something wrong without being catch by the tests ongetRep.To counter that, what would you think of testing all our components by rendering
Rep(props)instead of calling specific functions (e.g.String(props)) ?