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

Adding componentRef support, BaseComponent warnings, and initial Customizer component. #1389

Merged
merged 12 commits into from
Apr 4, 2017
Merged

Conversation

dzearing
Copy link
Member

@dzearing dzearing commented Apr 1, 2017

Addresses issue: #1356

This change is a subset of a much larger change, but this includes the important updates which are more general:

  • In components which are wrapped in a decorator or HOC, the "ref" ends up pointing to the wrong component, hiding all public methods (like focus().) In order to access the actual "ref", I'm adding support for resolving componentRef to the BaseComponent. This lets us pass through the callback to an inner component in decorator/HOC patterns. If you use BaseComponent as a base class, it will by default resolve it for you; you simply expose it in your Props definition. If you would like to avoid this being done because the inner component is doing it, you can set the protected _shouldUpdateComponentRef bool to false which will bypass resolution at that component layer.
  • Added the Customizer component and customizable decorator for injection. These helpers will enable us to inject new default props into components without requiring every individual component to be subclassed.
  • Deprecation maps should no longer be passed into the BaseComponent constructor. Instead you can use BaseComponent protected helpers _warnDeprecations and _warnMutuallyExclusive which will console.warn when deprecated things are being used.


return (results && results.length > 1) ? results[1] : '';
return this.__className;
Copy link
Member Author

Choose a reason for hiding this comment

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

memoizing the classname as an optimization.

* never changes.
*/
protected _onRenderNull(): JSX.Element | null {
return null;
Copy link
Member Author

Choose a reason for hiding this comment

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

Just as an fyi; I use this quite a bit in my other Button PR where i would like to return a function that renders nothing, but don't want to recreate it over and over (to avoid immutability issues)

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we move this to a const outside of a class?

Copy link
Member

Choose a reason for hiding this comment

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

These new warns are awesome. I want to make sure to communicate this to all developers. Considering a weekly React update to gather all of these new changes in a newsletter type form.

@@ -153,7 +235,7 @@ function _makeSafe(obj: BaseComponent<any, any>, prototype: Object, methodName:
if (prototypeMethod) {
retVal = prototypeMethod.apply(this, arguments);
}
if (classMethod) {
if (classMethod !== prototypeMethod) {
Copy link
Member Author

Choose a reason for hiding this comment

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

This is an important bug fix; Previously, it would call the prototypeMethod twice if the subclass doesn't implement it.

import { BaseComponent } from './BaseComponent';
import { assign } from './object';

export interface ISettings {
Copy link
Member Author

@dzearing dzearing Apr 1, 2017

Choose a reason for hiding this comment

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

I'd like to check this in as an initial implementation, but will add examples and refine this in a separate PR.

Note that this isn't being exported yet until we use it.

@@ -44,6 +61,16 @@ export class BaseComponent<P, S> extends React.Component<P, S> {
]);
}

/** When the component will receive props, make sure the componentRef is updated. */
public componentWillReceiveProps(newProps?: any, newContext?: any) {
Copy link
Contributor

Choose a reason for hiding this comment

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

P?

Copy link
Contributor

Choose a reason for hiding this comment

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

Or IBaseProps<P>?

* never changes.
*/
protected _onRenderNull(): JSX.Element | null {
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we move this to a const outside of a class?

@@ -0,0 +1,63 @@
let _warningCallback = _warn;

export interface IStringMap {
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

thx for the comments, will try

Copy link
Member Author

Choose a reason for hiding this comment

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

Good news! I did this, and it caught some bugs where I misplaced some warnings! Yay typings!

…tly works, even if the component doesn't have a public interface. Adding placeholder public interfaces, which exposes a number of inconsistencies across the components ( all of the focusable components should have focus methods, for example)
*/
componentRef?: (component: ICheckbox) => void;

/**
Copy link
Contributor

Choose a reason for hiding this comment

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

As discussed offline, I think it would be good if we could move this to an interface

interface IComponentRef<TComponent> {
  componentRef?: (component: TComponent)  => void;
}

and then add it to the component's props by extending multiple interfaces? Or by & it in BaseComponent? Shouldn't be a blocker for this change, but going forward it would be nice to centralize these shared props to make refactoring etc. easier.

@cschleiden
Copy link
Contributor

(Left it as a comment on an outdated, commit, repeating here for visibility)

As discussed offline, I think it would be good if we could move this (componentRef declaration) to an interface

interface IComponentRef<TComponent> {
  componentRef?: (component: TComponent)  => void;
}

and then add it to the component's props by extending multiple interfaces? Or by & it in BaseComponent? Shouldn't be a blocker for this change, but going forward it would be nice to centralize these shared props to make refactoring etc. easier.

…oving the deprecation map from BaseComponent, as it is conflicting with React's context when it is passed into the constructor.
@@ -38,17 +38,12 @@ export class BaseComponent<P extends IBaseProps, S> extends React.Component<P, S
* @param {Object} deprecatedProps The map of deprecated prop names to new names, where the key is the old name and the
Copy link
Contributor

Choose a reason for hiding this comment

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

update comment?

@@ -38,17 +38,12 @@ export class BaseComponent<P extends IBaseProps, S> extends React.Component<P, S
* @param {Object} deprecatedProps The map of deprecated prop names to new names, where the key is the old name and the
* value is the new name. If a prop is removed rather than renamed, leave the value undefined.
*/
constructor(props?: P, deprecationMap?: ISettingsMap<P>) {
constructor(props?: P) {
Copy link
Contributor

Choose a reason for hiding this comment

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

take context parameter and pass along?

@dzearing dzearing merged commit 086833b into microsoft:master Apr 4, 2017
@dzearing dzearing deleted the general-updates branch April 4, 2017 04:19
@microsoft microsoft locked as resolved and limited conversation to collaborators Aug 31, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants