如何在属性更改时重新生成反应组件

时间:2018-05-31 06:55:49

标签: javascript reactjs sharepoint spfx

所以我有这个反应组件,下拉属性(SPFx)有2个值,我需要在下拉列表更改时再次重新生成react,下拉列表定义从哪里检索值的数据源

Webpart.ts

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<IAbstractfactoryWebPartProps> {

  public render(): void {
    const element: React.ReactElement<IAbstractFactoryProps > = 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",
                  })
              ]
            }
          ]
        }
      ]
    };
  }
}

Component.tsx

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<IAbstractFactoryProps, IAbstractFactoryState> {
  //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<IAbstractFactoryProps> {
      return (
        <div className={ styles.abstractfactory }>
          <div className={ styles.container }>
            <div className={ styles.row }>
              <div className={ styles.column }>
              {this.state.items.map( i => (<div key={i.id}>{i.firstName}</div>))}
             </div>
            </div>
          </div>
        </div>
      );
    }

    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.
    }
}

国家

import Customer from "./Customer";

export interface IAbstractFactoryState {  
    items?: Customer[];
  }

DaoFactory

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";  

JsonCustomerDao.ts

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<Customer> = [c1, c2 ];
        return list;
    }
}

export default JsonCustomerDAO;

SharepointCustomerDao

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<Customer> = [c1, c2 ];
        return list;
    }
}

export default SharepointCustomerDao;

第一次执行为默认数据源呈现的值,但是当属性更改时,UI不会随新值一起更改。

我发现我可以使用此事件在下拉列表更改时设置新的道具数据源值

 protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
    this.properties[this.properties.datasource] = newValue;


    this.render();

    super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
  }

但是视图没有重新渲染,我可以使用任何react js事件来重新渲染或重新设置prop更改时的状态吗?

1 个答案:

答案 0 :(得分:1)

Reacts在数据更改时重新呈现组件的方法是更新它的状态。

例如,如果你有一个组件<Foo />,其中包含一个rendermethod来显示它的状态

...
render() {
   return(
     <div>Hello {this.state.name}</div>
   )
}
...

组件将显示Hello ,并且whetever位于state.name

每次更新给定组件的状态时都会重新渲染。因此,在您的情况下,如果您获得新项目,则必须将其推入州。一旦发生这种情况,react类将触发其render方法,并将使用当前状态显示新数据。

为了实现这一点,您需要一个从外部或组件内部调用的自定义方法。

例如

...
foo(receivesSomething) {
   const items = this.state.items;
   items.push(receivesSomething);
   this.setState({items}); // once a setState is being executed in any component react will make a diff between the current DOM and the ShadowDOM, if something is different then it will trigger a re-render of the affected component
}
... 

这篇文章编写得很好http://lucybain.com/blog/2017/react-js-when-to-rerender/并对其进行了解释。我建议你一般来看一下生命周期方法。

<强>更新

例如像这样。

class Foo extends React.Component {
   constructor(props){
      super();

      window.someFunction = payload => {
         // do whatever you want to do with the payload here
         this.setState({ items: payload });
      }

   }
}

<强> UPDATE2

如果您的组件正在侦听/接收道具,您可以使用componentWillReceiveProps(newProps)生命周期方法做出反应并更新其中的组件状态