title: How to re-render react component when a property changes
body: <p>so I have this react component, with a dropdown property (SPFx) which has 2 values, I need that when the dropdown is changed the react is re-rendered again, the dropdown defines the datasource from where the values will be retrieved.</p>
  
  <p>Webpart.ts</p>
  
  <pre><code>import * as React from 'react';
  import * as ReactDom from 'react-dom';
  import { Version } from '@microsoft/sp-core-library';
  import {  
    BaseClientSideWebPart,
    IPropertyPaneConfiguration,
    PropertyPaneDropdown
  } from "@microsoft/sp-webpart-base";
  
  import * as strings from 'AbstractfactoryWebPartStrings';
  import Abstractfactory from './components/Abstractfactory';
  import { IAbstractFactoryProps } from './components/IAbstractFactoryProps';
  import { IAbstractfactoryWebPartProps } from "./IAbstractfactoryWebPartProps";
  
  
  
  
  export default class AbstractfactoryWebPart extends BaseClientSideWebPart&lt;IAbstractfactoryWebPartProps&gt; {
  
    public render(): void {
      const element: React.ReactElement&lt;IAbstractFactoryProps &gt; = React.createElement(
        Abstractfactory,
        {
          datasource: this.properties.datasource
        }
      );
  
      ReactDom.render(element, this.domElement);
    }
  
    protected get dataVersion(): Version {
      return Version.parse('1.0');
    }
  
    protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
  
      super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
    }
  
    protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
      return {
        pages: [
          {
            header: {
              description: strings.PropertyPaneDescription
            },
            groups: [
              {
                groupName: strings.BasicGroupName,
                groupFields: [
                  PropertyPaneDropdown("datasource", {
                    label: "DataSource",
                    options: [
                        { key: "1", text: "Sharepoint"},
                        { key: "2", text: "JSON" }
                      ],
                    selectedKey: "1",
                    })
                ]
              }
            ]
          }
        ]
      };
    }
  }
  </code></pre>
  
  <p>Component.tsx</p>
  
  <pre><code>import * as React from 'react';
  import { IAbstractFactoryProps } from "./IAbstractFactoryProps";  
  import { IAbstractFactoryState } from "./IAbstractFactoryState";  
  import styles from './Abstractfactory.module.scss';
  import { escape } from '@microsoft/sp-lodash-subset';
  import DaoFactory from "./DaoFactory";  
  import ICustomerDao from "./ICustomerDao";  
  import DataSources from "./DatasourcesEnum";
  
  export default class Abstractfactory extends React.Component&lt;IAbstractFactoryProps, IAbstractFactoryState&gt; {
    //Private instance of customerDao, please note it returns ICustomerDao, an Interface,
      //not a concrete type
      private customerDao: ICustomerDao;
  
      constructor(props: IAbstractFactoryProps, state: IAbstractFactoryState) {
        super(props);
        this.setInitialState();
  
        // We set the Dao depending on the selected data source
        this.setDaos(props.datasource);
  
        //Then we set the list of customers and note, we dont care if they come from Sharepoint
        //Rest API or anything else.
        this.state = {
          items: this.customerDao.listCustomers(),
        };
      }
  
      public render(): React.ReactElement&lt;IAbstractFactoryProps&gt; {
        return (
          &lt;div className={ styles.abstractfactory }&gt;
            &lt;div className={ styles.container }&gt;
              &lt;div className={ styles.row }&gt;
                &lt;div className={ styles.column }&gt;
                {this.state.items.map( i =&gt; (&lt;div key={i.id}&gt;{i.firstName}&lt;/div&gt;))}
               &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        );
      }
  
      public setInitialState(): void {
        this.state = {
          items: []
        };
      }
  
      private setDaos(datasource: string): void {
        const data: DataSources = datasource === "Sharepoint" ? DataSources.SharepointList : DataSources.JsonData;
        this.customerDao = DaoFactory.getDAOFactory(data).getCustomerDAO();
  
        //Now, its transparent for us a UI developers what datasource was selected
        //this.customerDao.
      }
  }
  </code></pre>
  
  <p>State</p>
  
  <pre><code>import Customer from "./Customer";
  
  export interface IAbstractFactoryState {  
      items?: Customer[];
    }
  </code></pre>
  
  <p>DaoFactory</p>
  
  <pre><code>import ICustomerDAO from "./ICustomerDAO";  
  
  import DataSources from "./DatasourcesEnum";
  
  abstract class DAOFactory {
  
      //For each entity we will need to implement getCustomerDAO, this will make it easily replaceable
      //when another datasource comes in
      public abstract getCustomerDAO(): ICustomerDAO;
  
      //Static method that receives a parameter depending on the datasource and will return the specifc 
      //factory
      public  static getDAOFactory(whichFactory: DataSources): DAOFactory {
          switch (whichFactory) {
            case DataSources.SharepointList:
              return new SharepointListDAOFactory();
            case DataSources.JsonData:
              return new JsonDAOFactory();
            default  :
              return null;
          }
        }
  }
  
  export default DAOFactory;
  import SharepointListDAOFactory from "./SharepointListDAOFactory";  
  import JsonDAOFactory from "./JsonDAOFactory";  
  </code></pre>
  
  <p>JsonCustomerDao.ts</p>
  
  <pre><code>import ICustomerDao from "./ICustomerDao";  
  import Customer from "./Customer";
  
    class JsonCustomerDAO implements ICustomerDao{
      public insertCustomer(): number {
          // implementation to be done by reader
          return 1;
      }
  
      public deleteCustomer(): boolean {
          // implementation to be done by reader
          return true;
      }
  
      public findCustomer(): Customer {
          // implementation to be done by reader
          return new Customer();
      }
  
      public updateCustomer(): boolean {
          // implementation to be done by reader
          return true;
      }
  
      public listCustomers(): Customer[] {
          // implementation to be done by reader
          let c1: Customer= new Customer();
          let c2: Customer= new Customer();
          c1.id="3";
          c1.firstName="Andrew";
          c1.lastName="Valencia";
          c2.id="4";
          c2.firstName="Charles";
          c2.lastName="Smith";
  
  
          let list: Array&lt;Customer&gt; = [c1, c2 ];
          return list;
      }
  }
  
  export default JsonCustomerDAO;
  </code></pre>
  
  <p>SharepointCustomerDao</p>
  
  <pre><code>import ICustomerDao from "./ICustomerDao";  
  import Customer from "./Customer";
  
   class SharepointCustomerDao implements ICustomerDao {
      public insertCustomer(): number {
          // implementation to be done by reader
          return 1;
      }
  
      public deleteCustomer(): boolean {
           // implementation to be done by reader
          return true;
      }
  
      public findCustomer(): Customer {
           // implementation to be done by reader
          return new Customer();
      }
  
      public updateCustomer(): boolean {
           // implementation to be done by reader
          return true;
      }
  
      public listCustomers(): Customer[] {
           // implementation to be done by reader
          let c1: Customer = new Customer();
          c1.id="1";
          c1.firstName="Luis";
          c1.lastName="Valencia";
          let c2: Customer = new Customer();
          c2.id="2";
          c2.firstName="John";
          c2.lastName="Smith";
          let list: Array&lt;Customer&gt; = [c1, c2 ];
          return list;
      }
  }
  
  export default SharepointCustomerDao;
  </code></pre>
  
  <p>The first time its executed the values are rendered for the default datasource, but when the property changes, the UI is not changing with the new values.</p>
  
  <p>I found that I can use this event to set the new props datasource value when the dropdown changes</p>
  
  <pre><code> protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
      this.properties[this.properties.datasource] = newValue;
  
  
      this.render();
  
      super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
    }
  </code></pre>
  
  <p>However the view is not re-rendered, can I use any of the react js events to re-render or re-set the status when a prop is changed?</p>