Factory method done on reactjs component,

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
5
down vote

favorite












A Factory Pattern or Factory Method Pattern says that just define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate. In other words, subclasses are responsible to create the instance of the class.



Advantage of Factory Design Pattern
Factory Method Pattern allows the sub-classes to choose the type of objects to create. It promotes the loose-coupling by eliminating the need to bind application-specific classes into the code. That means the code interacts solely with the resultant interface or abstract class, so that it will work with any classes that implement that interface or that extends that abstract class.



A factory method is a method of a factory that builds objects



With that said, I built a React component that uses this pattern, functionally it works perfect, but I would like to know if the pattern is properly implemented or not and what your feedback as an expert is on this scenario.



enter image description here



Relevant source code:



ListItemFactory.ts



import SPHttpClient, SPHttpClientResponse from "@microsoft/sp-http";
import IWebPartContext from "@microsoft/sp-webpart-base";
import IListItem from "./models/IListItem";
import IFactory from "./IFactory";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";

export class ListItemFactory implements IFactory
// private _listItems: IListItem;
public getItems(requester: SPHttpClient, siteUrl: string, listName: string): Promise<any>
switch(listName)
case "GenericList":
let items: IListItem;
// tslint:disable-next-line:max-line-length
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Modified,Created,Author/Title,Editor/Title&$expand=Author,Editor`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IListItem > =>
return response.json();
)
.then((json: value: IListItem ) =>
console.log(JSON.stringify(json.value));
return items=json.value.map((v,i)=>(

// key: v.id,
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title

));
);
case "News":
let newsitems: INewsListItem;
// tslint:disable-next-line:max-line-length
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Modified,Created,Created By,Modified By,newsheader,newsbody,expiryDate`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: INewsListItem > =>
return response.json();
)
.then((json: value: INewsListItem ) =>
return newsitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
newsheader: v.newsheader,
newsbody: v.newsbody,
expiryDate: v.expiryDate

));
);
case "Announcements":
let announcementitems: IAnnouncementListItem;
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Created,Author/Title,Modified,Editor/Title,announcementBody,expiryDate&$expand=Author,Editor`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IAnnouncementListItem > =>
return response.json();
)
.then((json: value: IAnnouncementListItem ) =>
return announcementitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
announcementBody: v.announcementBody,
expiryDate: v.expiryDate

));
);
case "Directory":
let directoryitems: IDirectoryListItem;
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IDirectoryListItem > =>
return response.json();
)
.then((json: value: IDirectoryListItem ) =>
return directoryitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
firstName: v.firstName,
lastName: v.lastName,
mobileNumber: v.mobileNumber,
internalNumber: v.internalNumber

));
);
default:
break;





Ifactorystate.ts



import IListItem from "./models/IListItem";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";
import
IColumn
from "office-ui-fabric-react/lib/DetailsList";

export interface IFactoryMethodState
hasError: boolean;
status: string;
columns: IColumn;
DetailsListItemState: IDetailsListItemState;
DetailsNewsListItemState: IDetailsNewsListItemState;
DetailsDirectoryListItemState : IDetailsDirectoryListItemState;
DetailsAnnouncementsListItemState : IDetailsAnnouncementListItemState;


export interface IDetailsListItemState
items: IListItem;


export interface IDetailsNewsListItemState
items: INewsListItem;


export interface IDetailsDirectoryListItemState
items: IDirectoryListItem;


export interface IDetailsAnnouncementListItemState
items: IAnnouncementListItem;



and the component



//#region Imports
import * as React from "react";
import styles from "./FactoryMethod.module.scss";
import IFactoryMethodProps from "./IFactoryMethodProps";
import
IDetailsListItemState,
IDetailsNewsListItemState,
IDetailsDirectoryListItemState,
IDetailsAnnouncementListItemState,
IFactoryMethodState
from "./IFactoryMethodState";
import IListItem from "./models/IListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import escape from "@microsoft/sp-lodash-subset";
import SPHttpClient, SPHttpClientResponse from "@microsoft/sp-http";
import ListItemFactory from "./ListItemFactory";
import TextField from "office-ui-fabric-react/lib/TextField";
import
DetailsList,
DetailsListLayoutMode,
Selection,
buildColumns,
IColumn
from "office-ui-fabric-react/lib/DetailsList";
import MarqueeSelection from "office-ui-fabric-react/lib/MarqueeSelection";
import autobind from "office-ui-fabric-react/lib/Utilities";
import PropTypes from "prop-types";
//#endregion

export default class FactoryMethod extends React.Component<IFactoryMethodProps, IFactoryMethodState>
constructor(props: IFactoryMethodProps, state: any)
super(props);
this.setInitialState();



// lifecycle help here: https://staminaloops.github.io/undefinedisnotafunction/understanding-react/
//#region Mouting events lifecycle
// the data returned from render is neither a string nor a DOM node.
// it's a lightweight description of what the DOM should look like.
// inspects this.state and this.props and create the markup.
// when your data changes, the render method is called again.
// react diff the return value from the previous call to render with
// the new one, and generate a minimal set of changes to be applied to the DOM.
public render(): React.ReactElement<IFactoryMethodProps>
if (this.state.hasError)
// you can render any custom fallback UI
return <h1>Something went wrong.</h1>;
else
switch(this.props.listName)
case "GenericList":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsListItemState.items columns=this.state.columns />;
case "News":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsNewsListItemState.items columns=this.state.columns/>;
case "Announcements":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsAnnouncementsListItemState.items columns=this.state.columns/>;
case "Directory":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsDirectoryListItemState.items columns=this.state.columns/>;
default:
return null;




public componentDidCatch(error: any, info: any): void
// display fallback UI
this.setState( hasError: true );
// you can also log the error to an error reporting service
console.log(error);
console.log(info);




// componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here.
// if you need to load data from a remote endpoint, this is a good place to instantiate the network request.
// this method is a good place to set up any subscriptions. If you do that, don’t forget to unsubscribe in componentWillUnmount().
// calling setState() in this method will trigger an extra rendering, but it is guaranteed to flush during the same tick.
// this guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state.
// use this pattern with caution because it often causes performance issues. It can, however, be necessary for cases like modals and
// tooltips when you need to measure a DOM node before rendering something that depends on its size or position.
public componentDidMount(): void
this._configureWebPart = this._configureWebPart.bind(this);
this.readItemsAndSetStatus(this.props.listName);


//#endregion
//#region Props changes lifecycle events (after a property changes from parent component)
// componentWillReceiveProps() is invoked before a mounted component receives new props.
// if you need to update the state in response to prop
// changes (for example, to reset it), you may compare this.props and nextProps and perform state transitions
// using this.setState() in this method.
// note that React may call this method even if the props have not changed, so make sure to compare the current
// and next values if you only want to handle changes.
// this may occur when the parent component causes your component to re-render.
// react doesn’t call componentWillReceiveProps() with initial props during mounting. It only calls this
// method if some of component’s props may update
// calling this.setState() generally doesn’t trigger componentWillReceiveProps()
public componentWillReceiveProps(nextProps: IFactoryMethodProps): void
if(nextProps.listName !== this.props.listName)
this.readItemsAndSetStatus(nextProps.listName);



//#endregion
//#region private methods
private _configureWebPart(): void
this.props.configureStartCallback();


public setInitialState(): void
this.state =
hasError: false,
status: this.listNotConfigured(this.props)
? "Please configure list in Web Part properties"
: "Ready",
columns:,
DetailsListItemState:
items:
,
DetailsNewsListItemState:
items:
,
DetailsDirectoryListItemState:
items:
,
DetailsAnnouncementsListItemState:
items:
,
;


// reusable inline component
private ListMarqueeSelection = (itemState: columns: IColumn, items: IListItem ) => (
<div>
<DetailsList
items= itemState.items
columns= itemState.columns
setKey="set"
layoutMode= DetailsListLayoutMode.fixedColumns
selectionPreservedOnEmptyClick= true
compact= true >
</DetailsList>
</div>
)

// read items using factory method pattern and sets state accordingly
private readItemsAndSetStatus(listName): void
this.setState(
status: "Loading all items..."
);

const factory: ListItemFactory = new ListItemFactory();
factory.getItems(this.props.spHttpClient, this.props.siteUrl, listName

private listNotConfigured(props: IFactoryMethodProps): boolean
return props.listName === undefined

//#endregion







share|improve this question











migrated from stackoverflow.com May 27 at 12:48


This question came from our site for professional and enthusiast programmers.














  • the getItems method in the factory, depending on the selected list (returns/instantiates) an array of the type needed, the caller code does not have to worry about this. Thats my thinking but I could be wrong of course
    – Luis Valencia
    May 24 at 9:47










  • This isn't factory method. ListItemFactory isn't subclassed. It makes a request, not creates an instance. That you assign request result to item isn't considered 'class instance'. This is just a method with a big pile of code and some smell. It should be splitted into several different methods (or possibly classes - if you can make use of them). You're doing switch(this.props.listName) any way, you could call respective methods there. I guess the examples are self-explanatory, en.wikipedia.org/wiki/Factory_method_pattern#PHP , they have nothing to do with your case.
    – estus
    May 24 at 10:01
















up vote
5
down vote

favorite












A Factory Pattern or Factory Method Pattern says that just define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate. In other words, subclasses are responsible to create the instance of the class.



Advantage of Factory Design Pattern
Factory Method Pattern allows the sub-classes to choose the type of objects to create. It promotes the loose-coupling by eliminating the need to bind application-specific classes into the code. That means the code interacts solely with the resultant interface or abstract class, so that it will work with any classes that implement that interface or that extends that abstract class.



A factory method is a method of a factory that builds objects



With that said, I built a React component that uses this pattern, functionally it works perfect, but I would like to know if the pattern is properly implemented or not and what your feedback as an expert is on this scenario.



enter image description here



Relevant source code:



ListItemFactory.ts



import SPHttpClient, SPHttpClientResponse from "@microsoft/sp-http";
import IWebPartContext from "@microsoft/sp-webpart-base";
import IListItem from "./models/IListItem";
import IFactory from "./IFactory";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";

export class ListItemFactory implements IFactory
// private _listItems: IListItem;
public getItems(requester: SPHttpClient, siteUrl: string, listName: string): Promise<any>
switch(listName)
case "GenericList":
let items: IListItem;
// tslint:disable-next-line:max-line-length
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Modified,Created,Author/Title,Editor/Title&$expand=Author,Editor`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IListItem > =>
return response.json();
)
.then((json: value: IListItem ) =>
console.log(JSON.stringify(json.value));
return items=json.value.map((v,i)=>(

// key: v.id,
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title

));
);
case "News":
let newsitems: INewsListItem;
// tslint:disable-next-line:max-line-length
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Modified,Created,Created By,Modified By,newsheader,newsbody,expiryDate`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: INewsListItem > =>
return response.json();
)
.then((json: value: INewsListItem ) =>
return newsitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
newsheader: v.newsheader,
newsbody: v.newsbody,
expiryDate: v.expiryDate

));
);
case "Announcements":
let announcementitems: IAnnouncementListItem;
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Created,Author/Title,Modified,Editor/Title,announcementBody,expiryDate&$expand=Author,Editor`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IAnnouncementListItem > =>
return response.json();
)
.then((json: value: IAnnouncementListItem ) =>
return announcementitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
announcementBody: v.announcementBody,
expiryDate: v.expiryDate

));
);
case "Directory":
let directoryitems: IDirectoryListItem;
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IDirectoryListItem > =>
return response.json();
)
.then((json: value: IDirectoryListItem ) =>
return directoryitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
firstName: v.firstName,
lastName: v.lastName,
mobileNumber: v.mobileNumber,
internalNumber: v.internalNumber

));
);
default:
break;





Ifactorystate.ts



import IListItem from "./models/IListItem";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";
import
IColumn
from "office-ui-fabric-react/lib/DetailsList";

export interface IFactoryMethodState
hasError: boolean;
status: string;
columns: IColumn;
DetailsListItemState: IDetailsListItemState;
DetailsNewsListItemState: IDetailsNewsListItemState;
DetailsDirectoryListItemState : IDetailsDirectoryListItemState;
DetailsAnnouncementsListItemState : IDetailsAnnouncementListItemState;


export interface IDetailsListItemState
items: IListItem;


export interface IDetailsNewsListItemState
items: INewsListItem;


export interface IDetailsDirectoryListItemState
items: IDirectoryListItem;


export interface IDetailsAnnouncementListItemState
items: IAnnouncementListItem;



and the component



//#region Imports
import * as React from "react";
import styles from "./FactoryMethod.module.scss";
import IFactoryMethodProps from "./IFactoryMethodProps";
import
IDetailsListItemState,
IDetailsNewsListItemState,
IDetailsDirectoryListItemState,
IDetailsAnnouncementListItemState,
IFactoryMethodState
from "./IFactoryMethodState";
import IListItem from "./models/IListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import escape from "@microsoft/sp-lodash-subset";
import SPHttpClient, SPHttpClientResponse from "@microsoft/sp-http";
import ListItemFactory from "./ListItemFactory";
import TextField from "office-ui-fabric-react/lib/TextField";
import
DetailsList,
DetailsListLayoutMode,
Selection,
buildColumns,
IColumn
from "office-ui-fabric-react/lib/DetailsList";
import MarqueeSelection from "office-ui-fabric-react/lib/MarqueeSelection";
import autobind from "office-ui-fabric-react/lib/Utilities";
import PropTypes from "prop-types";
//#endregion

export default class FactoryMethod extends React.Component<IFactoryMethodProps, IFactoryMethodState>
constructor(props: IFactoryMethodProps, state: any)
super(props);
this.setInitialState();



// lifecycle help here: https://staminaloops.github.io/undefinedisnotafunction/understanding-react/
//#region Mouting events lifecycle
// the data returned from render is neither a string nor a DOM node.
// it's a lightweight description of what the DOM should look like.
// inspects this.state and this.props and create the markup.
// when your data changes, the render method is called again.
// react diff the return value from the previous call to render with
// the new one, and generate a minimal set of changes to be applied to the DOM.
public render(): React.ReactElement<IFactoryMethodProps>
if (this.state.hasError)
// you can render any custom fallback UI
return <h1>Something went wrong.</h1>;
else
switch(this.props.listName)
case "GenericList":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsListItemState.items columns=this.state.columns />;
case "News":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsNewsListItemState.items columns=this.state.columns/>;
case "Announcements":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsAnnouncementsListItemState.items columns=this.state.columns/>;
case "Directory":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsDirectoryListItemState.items columns=this.state.columns/>;
default:
return null;




public componentDidCatch(error: any, info: any): void
// display fallback UI
this.setState( hasError: true );
// you can also log the error to an error reporting service
console.log(error);
console.log(info);




// componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here.
// if you need to load data from a remote endpoint, this is a good place to instantiate the network request.
// this method is a good place to set up any subscriptions. If you do that, don’t forget to unsubscribe in componentWillUnmount().
// calling setState() in this method will trigger an extra rendering, but it is guaranteed to flush during the same tick.
// this guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state.
// use this pattern with caution because it often causes performance issues. It can, however, be necessary for cases like modals and
// tooltips when you need to measure a DOM node before rendering something that depends on its size or position.
public componentDidMount(): void
this._configureWebPart = this._configureWebPart.bind(this);
this.readItemsAndSetStatus(this.props.listName);


//#endregion
//#region Props changes lifecycle events (after a property changes from parent component)
// componentWillReceiveProps() is invoked before a mounted component receives new props.
// if you need to update the state in response to prop
// changes (for example, to reset it), you may compare this.props and nextProps and perform state transitions
// using this.setState() in this method.
// note that React may call this method even if the props have not changed, so make sure to compare the current
// and next values if you only want to handle changes.
// this may occur when the parent component causes your component to re-render.
// react doesn’t call componentWillReceiveProps() with initial props during mounting. It only calls this
// method if some of component’s props may update
// calling this.setState() generally doesn’t trigger componentWillReceiveProps()
public componentWillReceiveProps(nextProps: IFactoryMethodProps): void
if(nextProps.listName !== this.props.listName)
this.readItemsAndSetStatus(nextProps.listName);



//#endregion
//#region private methods
private _configureWebPart(): void
this.props.configureStartCallback();


public setInitialState(): void
this.state =
hasError: false,
status: this.listNotConfigured(this.props)
? "Please configure list in Web Part properties"
: "Ready",
columns:,
DetailsListItemState:
items:
,
DetailsNewsListItemState:
items:
,
DetailsDirectoryListItemState:
items:
,
DetailsAnnouncementsListItemState:
items:
,
;


// reusable inline component
private ListMarqueeSelection = (itemState: columns: IColumn, items: IListItem ) => (
<div>
<DetailsList
items= itemState.items
columns= itemState.columns
setKey="set"
layoutMode= DetailsListLayoutMode.fixedColumns
selectionPreservedOnEmptyClick= true
compact= true >
</DetailsList>
</div>
)

// read items using factory method pattern and sets state accordingly
private readItemsAndSetStatus(listName): void
this.setState(
status: "Loading all items..."
);

const factory: ListItemFactory = new ListItemFactory();
factory.getItems(this.props.spHttpClient, this.props.siteUrl, listName

private listNotConfigured(props: IFactoryMethodProps): boolean
return props.listName === undefined

//#endregion







share|improve this question











migrated from stackoverflow.com May 27 at 12:48


This question came from our site for professional and enthusiast programmers.














  • the getItems method in the factory, depending on the selected list (returns/instantiates) an array of the type needed, the caller code does not have to worry about this. Thats my thinking but I could be wrong of course
    – Luis Valencia
    May 24 at 9:47










  • This isn't factory method. ListItemFactory isn't subclassed. It makes a request, not creates an instance. That you assign request result to item isn't considered 'class instance'. This is just a method with a big pile of code and some smell. It should be splitted into several different methods (or possibly classes - if you can make use of them). You're doing switch(this.props.listName) any way, you could call respective methods there. I guess the examples are self-explanatory, en.wikipedia.org/wiki/Factory_method_pattern#PHP , they have nothing to do with your case.
    – estus
    May 24 at 10:01












up vote
5
down vote

favorite









up vote
5
down vote

favorite











A Factory Pattern or Factory Method Pattern says that just define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate. In other words, subclasses are responsible to create the instance of the class.



Advantage of Factory Design Pattern
Factory Method Pattern allows the sub-classes to choose the type of objects to create. It promotes the loose-coupling by eliminating the need to bind application-specific classes into the code. That means the code interacts solely with the resultant interface or abstract class, so that it will work with any classes that implement that interface or that extends that abstract class.



A factory method is a method of a factory that builds objects



With that said, I built a React component that uses this pattern, functionally it works perfect, but I would like to know if the pattern is properly implemented or not and what your feedback as an expert is on this scenario.



enter image description here



Relevant source code:



ListItemFactory.ts



import SPHttpClient, SPHttpClientResponse from "@microsoft/sp-http";
import IWebPartContext from "@microsoft/sp-webpart-base";
import IListItem from "./models/IListItem";
import IFactory from "./IFactory";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";

export class ListItemFactory implements IFactory
// private _listItems: IListItem;
public getItems(requester: SPHttpClient, siteUrl: string, listName: string): Promise<any>
switch(listName)
case "GenericList":
let items: IListItem;
// tslint:disable-next-line:max-line-length
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Modified,Created,Author/Title,Editor/Title&$expand=Author,Editor`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IListItem > =>
return response.json();
)
.then((json: value: IListItem ) =>
console.log(JSON.stringify(json.value));
return items=json.value.map((v,i)=>(

// key: v.id,
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title

));
);
case "News":
let newsitems: INewsListItem;
// tslint:disable-next-line:max-line-length
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Modified,Created,Created By,Modified By,newsheader,newsbody,expiryDate`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: INewsListItem > =>
return response.json();
)
.then((json: value: INewsListItem ) =>
return newsitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
newsheader: v.newsheader,
newsbody: v.newsbody,
expiryDate: v.expiryDate

));
);
case "Announcements":
let announcementitems: IAnnouncementListItem;
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Created,Author/Title,Modified,Editor/Title,announcementBody,expiryDate&$expand=Author,Editor`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IAnnouncementListItem > =>
return response.json();
)
.then((json: value: IAnnouncementListItem ) =>
return announcementitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
announcementBody: v.announcementBody,
expiryDate: v.expiryDate

));
);
case "Directory":
let directoryitems: IDirectoryListItem;
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IDirectoryListItem > =>
return response.json();
)
.then((json: value: IDirectoryListItem ) =>
return directoryitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
firstName: v.firstName,
lastName: v.lastName,
mobileNumber: v.mobileNumber,
internalNumber: v.internalNumber

));
);
default:
break;





Ifactorystate.ts



import IListItem from "./models/IListItem";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";
import
IColumn
from "office-ui-fabric-react/lib/DetailsList";

export interface IFactoryMethodState
hasError: boolean;
status: string;
columns: IColumn;
DetailsListItemState: IDetailsListItemState;
DetailsNewsListItemState: IDetailsNewsListItemState;
DetailsDirectoryListItemState : IDetailsDirectoryListItemState;
DetailsAnnouncementsListItemState : IDetailsAnnouncementListItemState;


export interface IDetailsListItemState
items: IListItem;


export interface IDetailsNewsListItemState
items: INewsListItem;


export interface IDetailsDirectoryListItemState
items: IDirectoryListItem;


export interface IDetailsAnnouncementListItemState
items: IAnnouncementListItem;



and the component



//#region Imports
import * as React from "react";
import styles from "./FactoryMethod.module.scss";
import IFactoryMethodProps from "./IFactoryMethodProps";
import
IDetailsListItemState,
IDetailsNewsListItemState,
IDetailsDirectoryListItemState,
IDetailsAnnouncementListItemState,
IFactoryMethodState
from "./IFactoryMethodState";
import IListItem from "./models/IListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import escape from "@microsoft/sp-lodash-subset";
import SPHttpClient, SPHttpClientResponse from "@microsoft/sp-http";
import ListItemFactory from "./ListItemFactory";
import TextField from "office-ui-fabric-react/lib/TextField";
import
DetailsList,
DetailsListLayoutMode,
Selection,
buildColumns,
IColumn
from "office-ui-fabric-react/lib/DetailsList";
import MarqueeSelection from "office-ui-fabric-react/lib/MarqueeSelection";
import autobind from "office-ui-fabric-react/lib/Utilities";
import PropTypes from "prop-types";
//#endregion

export default class FactoryMethod extends React.Component<IFactoryMethodProps, IFactoryMethodState>
constructor(props: IFactoryMethodProps, state: any)
super(props);
this.setInitialState();



// lifecycle help here: https://staminaloops.github.io/undefinedisnotafunction/understanding-react/
//#region Mouting events lifecycle
// the data returned from render is neither a string nor a DOM node.
// it's a lightweight description of what the DOM should look like.
// inspects this.state and this.props and create the markup.
// when your data changes, the render method is called again.
// react diff the return value from the previous call to render with
// the new one, and generate a minimal set of changes to be applied to the DOM.
public render(): React.ReactElement<IFactoryMethodProps>
if (this.state.hasError)
// you can render any custom fallback UI
return <h1>Something went wrong.</h1>;
else
switch(this.props.listName)
case "GenericList":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsListItemState.items columns=this.state.columns />;
case "News":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsNewsListItemState.items columns=this.state.columns/>;
case "Announcements":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsAnnouncementsListItemState.items columns=this.state.columns/>;
case "Directory":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsDirectoryListItemState.items columns=this.state.columns/>;
default:
return null;




public componentDidCatch(error: any, info: any): void
// display fallback UI
this.setState( hasError: true );
// you can also log the error to an error reporting service
console.log(error);
console.log(info);




// componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here.
// if you need to load data from a remote endpoint, this is a good place to instantiate the network request.
// this method is a good place to set up any subscriptions. If you do that, don’t forget to unsubscribe in componentWillUnmount().
// calling setState() in this method will trigger an extra rendering, but it is guaranteed to flush during the same tick.
// this guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state.
// use this pattern with caution because it often causes performance issues. It can, however, be necessary for cases like modals and
// tooltips when you need to measure a DOM node before rendering something that depends on its size or position.
public componentDidMount(): void
this._configureWebPart = this._configureWebPart.bind(this);
this.readItemsAndSetStatus(this.props.listName);


//#endregion
//#region Props changes lifecycle events (after a property changes from parent component)
// componentWillReceiveProps() is invoked before a mounted component receives new props.
// if you need to update the state in response to prop
// changes (for example, to reset it), you may compare this.props and nextProps and perform state transitions
// using this.setState() in this method.
// note that React may call this method even if the props have not changed, so make sure to compare the current
// and next values if you only want to handle changes.
// this may occur when the parent component causes your component to re-render.
// react doesn’t call componentWillReceiveProps() with initial props during mounting. It only calls this
// method if some of component’s props may update
// calling this.setState() generally doesn’t trigger componentWillReceiveProps()
public componentWillReceiveProps(nextProps: IFactoryMethodProps): void
if(nextProps.listName !== this.props.listName)
this.readItemsAndSetStatus(nextProps.listName);



//#endregion
//#region private methods
private _configureWebPart(): void
this.props.configureStartCallback();


public setInitialState(): void
this.state =
hasError: false,
status: this.listNotConfigured(this.props)
? "Please configure list in Web Part properties"
: "Ready",
columns:,
DetailsListItemState:
items:
,
DetailsNewsListItemState:
items:
,
DetailsDirectoryListItemState:
items:
,
DetailsAnnouncementsListItemState:
items:
,
;


// reusable inline component
private ListMarqueeSelection = (itemState: columns: IColumn, items: IListItem ) => (
<div>
<DetailsList
items= itemState.items
columns= itemState.columns
setKey="set"
layoutMode= DetailsListLayoutMode.fixedColumns
selectionPreservedOnEmptyClick= true
compact= true >
</DetailsList>
</div>
)

// read items using factory method pattern and sets state accordingly
private readItemsAndSetStatus(listName): void
this.setState(
status: "Loading all items..."
);

const factory: ListItemFactory = new ListItemFactory();
factory.getItems(this.props.spHttpClient, this.props.siteUrl, listName

private listNotConfigured(props: IFactoryMethodProps): boolean
return props.listName === undefined

//#endregion







share|improve this question











A Factory Pattern or Factory Method Pattern says that just define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate. In other words, subclasses are responsible to create the instance of the class.



Advantage of Factory Design Pattern
Factory Method Pattern allows the sub-classes to choose the type of objects to create. It promotes the loose-coupling by eliminating the need to bind application-specific classes into the code. That means the code interacts solely with the resultant interface or abstract class, so that it will work with any classes that implement that interface or that extends that abstract class.



A factory method is a method of a factory that builds objects



With that said, I built a React component that uses this pattern, functionally it works perfect, but I would like to know if the pattern is properly implemented or not and what your feedback as an expert is on this scenario.



enter image description here



Relevant source code:



ListItemFactory.ts



import SPHttpClient, SPHttpClientResponse from "@microsoft/sp-http";
import IWebPartContext from "@microsoft/sp-webpart-base";
import IListItem from "./models/IListItem";
import IFactory from "./IFactory";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";

export class ListItemFactory implements IFactory
// private _listItems: IListItem;
public getItems(requester: SPHttpClient, siteUrl: string, listName: string): Promise<any>
switch(listName)
case "GenericList":
let items: IListItem;
// tslint:disable-next-line:max-line-length
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Modified,Created,Author/Title,Editor/Title&$expand=Author,Editor`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IListItem > =>
return response.json();
)
.then((json: value: IListItem ) =>
console.log(JSON.stringify(json.value));
return items=json.value.map((v,i)=>(

// key: v.id,
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title

));
);
case "News":
let newsitems: INewsListItem;
// tslint:disable-next-line:max-line-length
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Modified,Created,Created By,Modified By,newsheader,newsbody,expiryDate`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: INewsListItem > =>
return response.json();
)
.then((json: value: INewsListItem ) =>
return newsitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
newsheader: v.newsheader,
newsbody: v.newsbody,
expiryDate: v.expiryDate

));
);
case "Announcements":
let announcementitems: IAnnouncementListItem;
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id,Created,Author/Title,Modified,Editor/Title,announcementBody,expiryDate&$expand=Author,Editor`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IAnnouncementListItem > =>
return response.json();
)
.then((json: value: IAnnouncementListItem ) =>
return announcementitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
announcementBody: v.announcementBody,
expiryDate: v.expiryDate

));
);
case "Directory":
let directoryitems: IDirectoryListItem;
return requester.get(`$siteUrl/_api/web/lists/getbytitle('$listName')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,

headers:
"Accept": "application/json;odata=nometadata",
"odata-version": ""

)
.then((response: SPHttpClientResponse): Promise< value: IDirectoryListItem > =>
return response.json();
)
.then((json: value: IDirectoryListItem ) =>
return directoryitems=json.value.map((v,i)=>(

id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
firstName: v.firstName,
lastName: v.lastName,
mobileNumber: v.mobileNumber,
internalNumber: v.internalNumber

));
);
default:
break;





Ifactorystate.ts



import IListItem from "./models/IListItem";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";
import
IColumn
from "office-ui-fabric-react/lib/DetailsList";

export interface IFactoryMethodState
hasError: boolean;
status: string;
columns: IColumn;
DetailsListItemState: IDetailsListItemState;
DetailsNewsListItemState: IDetailsNewsListItemState;
DetailsDirectoryListItemState : IDetailsDirectoryListItemState;
DetailsAnnouncementsListItemState : IDetailsAnnouncementListItemState;


export interface IDetailsListItemState
items: IListItem;


export interface IDetailsNewsListItemState
items: INewsListItem;


export interface IDetailsDirectoryListItemState
items: IDirectoryListItem;


export interface IDetailsAnnouncementListItemState
items: IAnnouncementListItem;



and the component



//#region Imports
import * as React from "react";
import styles from "./FactoryMethod.module.scss";
import IFactoryMethodProps from "./IFactoryMethodProps";
import
IDetailsListItemState,
IDetailsNewsListItemState,
IDetailsDirectoryListItemState,
IDetailsAnnouncementListItemState,
IFactoryMethodState
from "./IFactoryMethodState";
import IListItem from "./models/IListItem";
import IAnnouncementListItem from "./models/IAnnouncementListItem";
import INewsListItem from "./models/INewsListItem";
import IDirectoryListItem from "./models/IDirectoryListItem";
import escape from "@microsoft/sp-lodash-subset";
import SPHttpClient, SPHttpClientResponse from "@microsoft/sp-http";
import ListItemFactory from "./ListItemFactory";
import TextField from "office-ui-fabric-react/lib/TextField";
import
DetailsList,
DetailsListLayoutMode,
Selection,
buildColumns,
IColumn
from "office-ui-fabric-react/lib/DetailsList";
import MarqueeSelection from "office-ui-fabric-react/lib/MarqueeSelection";
import autobind from "office-ui-fabric-react/lib/Utilities";
import PropTypes from "prop-types";
//#endregion

export default class FactoryMethod extends React.Component<IFactoryMethodProps, IFactoryMethodState>
constructor(props: IFactoryMethodProps, state: any)
super(props);
this.setInitialState();



// lifecycle help here: https://staminaloops.github.io/undefinedisnotafunction/understanding-react/
//#region Mouting events lifecycle
// the data returned from render is neither a string nor a DOM node.
// it's a lightweight description of what the DOM should look like.
// inspects this.state and this.props and create the markup.
// when your data changes, the render method is called again.
// react diff the return value from the previous call to render with
// the new one, and generate a minimal set of changes to be applied to the DOM.
public render(): React.ReactElement<IFactoryMethodProps>
if (this.state.hasError)
// you can render any custom fallback UI
return <h1>Something went wrong.</h1>;
else
switch(this.props.listName)
case "GenericList":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsListItemState.items columns=this.state.columns />;
case "News":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsNewsListItemState.items columns=this.state.columns/>;
case "Announcements":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsAnnouncementsListItemState.items columns=this.state.columns/>;
case "Directory":
// tslint:disable-next-line:max-line-length
return <this.ListMarqueeSelection items=this.state.DetailsDirectoryListItemState.items columns=this.state.columns/>;
default:
return null;




public componentDidCatch(error: any, info: any): void
// display fallback UI
this.setState( hasError: true );
// you can also log the error to an error reporting service
console.log(error);
console.log(info);




// componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here.
// if you need to load data from a remote endpoint, this is a good place to instantiate the network request.
// this method is a good place to set up any subscriptions. If you do that, don’t forget to unsubscribe in componentWillUnmount().
// calling setState() in this method will trigger an extra rendering, but it is guaranteed to flush during the same tick.
// this guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state.
// use this pattern with caution because it often causes performance issues. It can, however, be necessary for cases like modals and
// tooltips when you need to measure a DOM node before rendering something that depends on its size or position.
public componentDidMount(): void
this._configureWebPart = this._configureWebPart.bind(this);
this.readItemsAndSetStatus(this.props.listName);


//#endregion
//#region Props changes lifecycle events (after a property changes from parent component)
// componentWillReceiveProps() is invoked before a mounted component receives new props.
// if you need to update the state in response to prop
// changes (for example, to reset it), you may compare this.props and nextProps and perform state transitions
// using this.setState() in this method.
// note that React may call this method even if the props have not changed, so make sure to compare the current
// and next values if you only want to handle changes.
// this may occur when the parent component causes your component to re-render.
// react doesn’t call componentWillReceiveProps() with initial props during mounting. It only calls this
// method if some of component’s props may update
// calling this.setState() generally doesn’t trigger componentWillReceiveProps()
public componentWillReceiveProps(nextProps: IFactoryMethodProps): void
if(nextProps.listName !== this.props.listName)
this.readItemsAndSetStatus(nextProps.listName);



//#endregion
//#region private methods
private _configureWebPart(): void
this.props.configureStartCallback();


public setInitialState(): void
this.state =
hasError: false,
status: this.listNotConfigured(this.props)
? "Please configure list in Web Part properties"
: "Ready",
columns:,
DetailsListItemState:
items:
,
DetailsNewsListItemState:
items:
,
DetailsDirectoryListItemState:
items:
,
DetailsAnnouncementsListItemState:
items:
,
;


// reusable inline component
private ListMarqueeSelection = (itemState: columns: IColumn, items: IListItem ) => (
<div>
<DetailsList
items= itemState.items
columns= itemState.columns
setKey="set"
layoutMode= DetailsListLayoutMode.fixedColumns
selectionPreservedOnEmptyClick= true
compact= true >
</DetailsList>
</div>
)

// read items using factory method pattern and sets state accordingly
private readItemsAndSetStatus(listName): void
this.setState(
status: "Loading all items..."
);

const factory: ListItemFactory = new ListItemFactory();
factory.getItems(this.props.spHttpClient, this.props.siteUrl, listName

private listNotConfigured(props: IFactoryMethodProps): boolean
return props.listName === undefined

//#endregion









share|improve this question










share|improve this question




share|improve this question









asked May 24 at 8:41









Luis Valencia

105112




105112




migrated from stackoverflow.com May 27 at 12:48


This question came from our site for professional and enthusiast programmers.






migrated from stackoverflow.com May 27 at 12:48


This question came from our site for professional and enthusiast programmers.













  • the getItems method in the factory, depending on the selected list (returns/instantiates) an array of the type needed, the caller code does not have to worry about this. Thats my thinking but I could be wrong of course
    – Luis Valencia
    May 24 at 9:47










  • This isn't factory method. ListItemFactory isn't subclassed. It makes a request, not creates an instance. That you assign request result to item isn't considered 'class instance'. This is just a method with a big pile of code and some smell. It should be splitted into several different methods (or possibly classes - if you can make use of them). You're doing switch(this.props.listName) any way, you could call respective methods there. I guess the examples are self-explanatory, en.wikipedia.org/wiki/Factory_method_pattern#PHP , they have nothing to do with your case.
    – estus
    May 24 at 10:01
















  • the getItems method in the factory, depending on the selected list (returns/instantiates) an array of the type needed, the caller code does not have to worry about this. Thats my thinking but I could be wrong of course
    – Luis Valencia
    May 24 at 9:47










  • This isn't factory method. ListItemFactory isn't subclassed. It makes a request, not creates an instance. That you assign request result to item isn't considered 'class instance'. This is just a method with a big pile of code and some smell. It should be splitted into several different methods (or possibly classes - if you can make use of them). You're doing switch(this.props.listName) any way, you could call respective methods there. I guess the examples are self-explanatory, en.wikipedia.org/wiki/Factory_method_pattern#PHP , they have nothing to do with your case.
    – estus
    May 24 at 10:01















the getItems method in the factory, depending on the selected list (returns/instantiates) an array of the type needed, the caller code does not have to worry about this. Thats my thinking but I could be wrong of course
– Luis Valencia
May 24 at 9:47




the getItems method in the factory, depending on the selected list (returns/instantiates) an array of the type needed, the caller code does not have to worry about this. Thats my thinking but I could be wrong of course
– Luis Valencia
May 24 at 9:47












This isn't factory method. ListItemFactory isn't subclassed. It makes a request, not creates an instance. That you assign request result to item isn't considered 'class instance'. This is just a method with a big pile of code and some smell. It should be splitted into several different methods (or possibly classes - if you can make use of them). You're doing switch(this.props.listName) any way, you could call respective methods there. I guess the examples are self-explanatory, en.wikipedia.org/wiki/Factory_method_pattern#PHP , they have nothing to do with your case.
– estus
May 24 at 10:01




This isn't factory method. ListItemFactory isn't subclassed. It makes a request, not creates an instance. That you assign request result to item isn't considered 'class instance'. This is just a method with a big pile of code and some smell. It should be splitted into several different methods (or possibly classes - if you can make use of them). You're doing switch(this.props.listName) any way, you could call respective methods there. I guess the examples are self-explanatory, en.wikipedia.org/wiki/Factory_method_pattern#PHP , they have nothing to do with your case.
– estus
May 24 at 10:01















active

oldest

votes











Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195263%2ffactory-method-done-on-reactjs-component%23new-answer', 'question_page');

);

Post as a guest



































active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes










 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195263%2ffactory-method-done-on-reactjs-component%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Greedy Best First Search implementation in Rust

Function to Return a JSON Like Objects Using VBA Collections and Arrays

C++11 CLH Lock Implementation