I'm working on a spfx app to be used as a SharePoint list form. The app will be used to edit ha a LOT of lookup columns. the lookup columns are rendered as dropdowns in the react component. I am currently fetching the list item to be rendered as well as all the data from all the lookup columns in the render method of the web part, and then passing the item to be edited and the values of all the lookup columns(the complete list) as state to the react component when I call ReactDom.render so that it can render the dropdowns.
This is slow. Its waiting to get all possible values for all columns before rendering the component. I have users in Australia and our tenant is in US-East.
What I want to do is fetch just the item to be edited and render the component. The component should render with the dropdowns having only one value-- the value currently selected on the item to be edited, I can achieve this by using the expands on pnp-js-core. Then, asynchronously, I want to fetch the full set of lookup column values to be passed to the react component and send them down later. That way the page displays quickly, and by the time the user clicks a dropdown, the values will have hopefully been loaded. I see the react component has a componentWillReceiveProps method. How do I pass updated props to the react component from the web part after it has been mounted/rendered?
I can put code it the compnentDidMount, bit that would get ugly (lookup values belong in the state)
Current state:
public render(): void {
let formProps: ITrFormProps = {
customers: [], //lookup info
techSpecs: [], // lookup info
requestors: [], // lookup info
tr: new TR(), // the thing i am editing
};
let batch = pnp.sp.createBatch();
get customers using the batch
get techSpecs using the batch
get requestors using the batch
get the data i want to edit using the batch
batch.execute().then((value) => {
this.reactElement = React.createElement(TrForm, formProps);
}
Desired state:
public render(): void {
let formProps: ITrFormProps = {
customers: [], //lookup info
techSpecs: [], // lookup info
requestors: [], // lookup info
tr: new TR(), // the thing i am editing
};
let batch = pnp.sp.createBatch();
get the data i want to edit using the batch
batch.execute().then((value) => {
set the LOOKUPS to be an aray of one element, just the value in the item i am editing
this.reactElement = React.createElement(TrForm, formProps).then((value) => {
let batch2 = pnp.sp.createBatch();
get customers using the batch
get techSpecs using the batch
get requestors using the batch
batch.execute().then((value) => {
/***** HOW DO I UPDATE THE COMPONET WITH THE NEW STATE***
}
}
UPDATE: I did get it to work by using this code after the initial item was fetched:
batch.execute().then((value) => {// execute the batch to get the item being edited and info REQUIRED for initial display
this.reactElement = React.createElement(TrForm, formProps);
var formComponent: TrForm = ReactDom.render(this.reactElement, this.domElement) as TrForm;//render the component
let batch2 = pnp.sp.createBatch(); // create a second batch to get the lookup columns
pnp.sp.web.lists.getByTitle(this.properties.partyListName).items.inBatch(batch2).get()// get the lookup info
.then((items) => {
formProps.customers = _.map(items, (item) => {
return new Customer(item["Id"], item["Title"]);
});
})
.catch((error) => {
console.log("ERROR, An error occured fetching 'Customers'");
console.log(error.message);
});
batch2.execute().then(() => {
// formComponent.props = formProps; this did not work
formComponent.props.customers = formProps.customers;// set the lookup values on the components props
formComponent.forceUpdate(); // make it redraw
});
}
);
This is quite ugly. I have no idea why formComponent.props = formProps did not work. There must be a better way.