We saw the use of runAfterSave as a function that set the entity id and entityname on our components using method calls. This approach is not very react oriented which is much more about state being passed down as props from the parent component. While redux and other toolkits suggest injecting state directly into the component is Ok, e.g. an observable changes and the props on a component changes, we can do something a bit simpler.
We'll leave it as an exercise on how to change the runAfterSave into an observable. Here, we will create a simple parent component that passes down entityId and entityName to a single child component when values are available. We'll also create a simple component that provides the Xrm context as a context that any sub-component can access directly.
Dynamics Wrapper
Much like the redux wrapper that provides a store to child components, we can provide Xrm as part of a context. This allows components to use a consistent approach to obtaining Xrm when needed.
// import a definition of Xrm...exportinterfaceNotifier {add: (p: {message:string, removeAfter:number, level:string}) =>stringremove: (token:string) =>void}exportinterfaceErrorHandler {// or whatever...report: (message:string) =>void}exportinterfaceDynamicsContext { Xrm:Xrm|null notifier:Notifier errorHandler:ErrorHandler}exportinterfaceDynamicsPropsextendsPartial<DynamcisContext> {}classDynamics<PextendsDynamicsProps=DynamicsProps,S={}> extendsReact.Component<Props,S> {constructor(props,context) {super(props, context) }private defaultErrorHandler:ErrorHandler=newConsoleErrorHandler()private defaultNotifier:Notifier=newNotificationManager(() =>this.getXrm())getChildContext():DynamicsContext {console.log("getChildContext")return { notifier:this.props.notifier ? (this.props.notifier asNotifier) :this.defaultNotifier, Xrm:this.getXrm() ||null, errorHandler:this.props.errorHandler ? (this.props.errorHandler asErrorHandler):this.defaultErrorHandler } }/** Get Xrm from the props or the global environment. */protectedgetXrm():Xrm|null {if(typeofthis.props.Xrm !=="undefined"&&this.props.Xrm !==null)returnthis.props.Xrm asXrmreturnUtils.getXrm() }static childContextTypes = { notifier:PropTypes.object, Xrm:PropTypes.object, errorHandler:PropTypes.object }render() {const { children } =this.props;returnReact.Children.only(children) }}
The use of default types in Dynamics allows this to be properly extended or used directly without specifying the property type. Your class could subclass this, but its better to be used as a container. You could also use recompose to make this into something composable using just a function.
We can easily extend Dynamics to include entityid logic and use this when we are working with entities:
classEntityForm<P,S> extendsDynamics<P,S> {[cut and paste]}
Your component would just use the standard componentWillReceiveProps to nab the new "entityId" state on its change, for example if you are on a "create" form and the entity is saved, we need to have the "entity" be consumed.
classMyComponent {...constructor(props) {// store initial value in state if needed...this.state = { entityId:props.entityId ||null } }// Grab entityId for the state if case you need it for your state// you may not need it in your state.publiccomponentWillReceiveProps(nextProps,nextContext) {if(nextProps.entityId !==this.state.entityId) {this.setState({entityId:nextProps.entityId})// fetch some data and update data state based on the entityId and entityName// ... }render() {// You could use props or state here.if(!this.props.entityId) return (<div>No id!</div>)return(<div>{this.props.entityId}</ }}
Simple Notifier
We mentioned the notifier above. Since we have a react component, we can maintain the state of a notification in our component state then remove the message after a certain time...or do other tricks.