当属性更改时如何重新渲染反应组件

2024-01-08

所以我有这个反应组件,带有一个具有 2 个值的下拉属性(SPFx),我需要当下拉列表更改时再次重新渲染反应,下拉列表定义从中检索值的数据源。

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",
                  })
              ]
            }
          ]
        }
      ]
    };
  }
}

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

State

import Customer from "./Customer";

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

道工厂

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 不会随新值而更改。

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

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


    this.render();

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

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


在数据更改时重新渲染组件的 React 方法是更新其状态。

例如,如果您有一个组件<Foo />其中包含一个渲染方法来显示它的状态,例如

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

该组件将显示 Hello以及是否在 state.name 中

每次更新给定组件的状态时都会发生重新渲染。因此,就您而言,如果您获得新物品,则必须将它们推入该状态。一旦发生这种情况,反应类将触发其渲染方法并使用当前状态来显示新数据。

为此,您需要一个从外部或组件内部调用的自定义方法。

例如

...
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/ http://lucybain.com/blog/2017/react-js-when-to-rerender/并对其进行了一些解释。我建议您也研究一下一般的生命周期方法。

update

比如像这样。

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)React 的生命周期方法并更新其中的组件状态

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当属性更改时如何重新渲染反应组件 的相关文章

随机推荐