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

Centralized handling shouldComponentUpdate into SchemaField #490

Merged
merged 5 commits into from
Mar 2, 2017

Conversation

knilink
Copy link
Contributor

@knilink knilink commented Feb 25, 2017

Reasons for making this change

When one property is updated, the rest of the properties will be unnecessarily rendered.
This will cause a significant performance issue in a large object schema such as the demo of 'Large' in the playground.

Checklist

  • I'm updating documentation
    • I've checked the rendering of the Markdown text I've added
    • If I'm adding a new section, I've updated the Table of Content
  • I'm adding or updating code
    • I've added and/or updated tests
    • I've updated docs if needed
  • I'm adding a new feature
    • I've updated the playground with an example use of the feature

Copy link
Collaborator

@n1k0 n1k0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for your work :)

A few questions with the patch.

// idSchema and errorSchema will be equal
delete _props.idSchema;
delete _nextProps.idSchema;
return !deepEquals(_props, _nextProps);
Copy link
Collaborator

@n1k0 n1k0 Feb 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused with this code:

  1. the implementation doesn't reflect what the comment says; we're not dropping errorSchema;
  2. the comment suggests we should only compare changes for schema and formData, which is not what we're doing;
  3. I suspect we should take care of uiSchema changes as well.

I'm trying to summarize the points above in a sample implementation below:

shouldComponentUpdate(nextProps) {
  return !deepEquals(this.props.formData, nextProps.formData) ||
         !deepEquals(this.props.schema, nextProps.schema) ||
         !deepEquals(this.props.uiSchema, nextProps.uiSchema);
}

We may obviously want to ensure we're not missing other necessary checks, but I'm finding this way much more explicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment suggests that "schema" and "formData" didn't change => "idSchema" and "errorSchema" didn't change. So, comparing "schema" and "formData" is enough to tell wheter "idSchema" and "errorSchema" have change or not.
But, not comparing errorSchema will fail some test. I haven't figure out the reason yet. And, the performance with comparing errorSchema looks acceptable.
I will update the comment.

if (Object.keys(schema).length === 0) {
// See #312: Ensure compatibility with old versions of React.
return <div/>;
class SchemaField extends Component {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's really sad there's no way to have the equivalent of shouldComponentUpdate for stateless components. I could totally see a decorator of some sort.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think React still need an instance to preserve props in order to have both "this.props" and "nextProps" to compare. recompose is one library I know to do such a thing. It will turn functions into classes.


sinon.assert.notCalled(comp.render);
});
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why has this test been removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "shouldComponnetUpdate" of "ObjectField" and "ArrayField" were guaranteed by "SchemaField". So, I thought those two function were no longer necessary and the related tests were removed.

Copy link
Collaborator

@n1k0 n1k0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty good! Thanks for this. A few formatting nits and we're good to go.

);
}

render(){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: space before opening bracket

sandbox.stub(fieldComp, "render").returns(<div/>);
fields[fieldComp.props.idSchema.$id] = fieldComp;
return fields;
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: let's apply a consistent coding style:

const fields = scryRenderedComponentsWithType(comp, SchemaField)
  .reduce((fields, fieldComp) => {
    sandbox.stub(fieldComp, "render").returns(<div/>);
    fields[fieldComp.props.idSchema.$id] = fieldComp;
    return fields;
  });

@n1k0
Copy link
Collaborator

n1k0 commented Mar 2, 2017

Thank you 👍

@n1k0 n1k0 merged commit 241ace3 into rjsf-team:master Mar 2, 2017
n1k0 added a commit that referenced this pull request Mar 21, 2017
New features

* Add support for rows attribute of textarea widget. (#450)
* #434 - Render empty array item fields when minItems is specified (#484)
* Add a "has-danger" class to the form error list (#502)
* Show description for boolean fields (#498)
* Fix #488: Add a custom Form ErrorList prop.

Bugfixes

* Fix impossibility to use stateful ArrayFieldTeplate comp. (#519)
* Centralized shouldComponentUpdate handling in SchemaField (#490)
@n1k0
Copy link
Collaborator

n1k0 commented Mar 21, 2017

Released in v0.44.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants