属性更改时如何重新渲染反应组件 [英] How to re-render react component when a property changes

查看:21
本文介绍了属性更改时如何重新渲染反应组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有这个 react 组件,它有一个下拉属性 (SPFx),它有 2 个值,我需要当下拉列表更改时,react 再次重新呈现,下拉列表定义了从中检索值的数据源.

Webpart.ts

import * as React from 'react';从 'react-dom' 导入 * 作为 ReactDom;从@microsoft/sp-core-library"导入{版本};进口 {BaseClientSideWebPart,IPropertyPaneConfiguration,属性面板下拉菜单} 来自@microsoft/sp-webpart-base";从 'AbstractfactoryWebPartStrings' 导入 * 作为字符串;从'./components/Abstractfactory'导入抽象工厂;从'./components/IAbstractFactoryProps'导入{IAbstractFactoryProps};import { IAbstractfactoryWebPartProps } from "./IAbstractfactoryWebPartProps";导出默认类 AbstractfactoryWebPart 扩展 BaseClientSideWebPart<IAbstractfactoryWebPartProps>{公共渲染():无效{const 元素:React.ReactElement<IAbstractFactoryProps>= React.createElement(抽象工厂,{数据源:this.properties.datasource});ReactDom.render(element, this.domElement);}受保护的获取数据版本():版本{返回 Version.parse('1.0');}protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);}受保护的 getPropertyPaneConfiguration(): IPropertyPaneConfiguration {返回 {页数:[{标题:{描述:strings.PropertyPaneDescription},组: [{组名:strings.BasicGroupName,组字段:[PropertyPaneDropdown("数据源", {标签:数据源",选项: [{ key: "1", text: "Sharepoint"},{ 键:2",文本:JSON"}],selectedKey: "1",})]}]}]};}}

组件.tsx

import * as React from 'react';import { IAbstractFactoryProps } from "./IAbstractFactoryProps";import { IAbstractFactoryState } from "./IAbstractFactoryState";从'./Abstractfactory.module.scss'导入样式;从'@microsoft/sp-lodash-subset'导入{转义};从./DaoFactory"导入DaoFactory;从./ICustomerDao"导入 ICustomerDao;从./DatasourcesEnum"导入数据源;导出默认类 Abstractfactory 扩展 React.Component{//customerDao 的私有实例,请注意它返回 ICustomerDao,一个接口,//不是具体类型私人 customerDao:ICustomerDao;构造函数(道具:IAbstractFactoryProps,状态:IAbstractFactoryState){超级(道具);this.setInitialState();//我们根据选择的数据源设置 Daothis.setDaos(props.datasource);//然后我们设置客户列表并注意,我们不关心他们是否来自Sharepoint//休息API或其他任何东西.this.state = {项目:this.customerDao.listCustomers(),};}公共渲染():React.ReactElement<IAbstractFactoryProps>{返回 (<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>))}

);}公共 setInitialState(): 无效 {this.state = {项目: []};}私有 setDaos(数据源:字符串):无效 {const 数据:DataSources = datasource === "Sharepoint" ?DataSources.SharepointList : DataSources.JsonData;this.customerDao = DaoFactory.getDAOFactory(data).getCustomerDAO();//现在,它对我们 UI 开发人员来说是透明的,选择了什么数据源//this.customerDao.}}

状态

从./Customer"导入客户;导出接口 IAbstractFactoryState {项目?:客户[];}

道工厂

从./ICustomerDAO"导入ICustomerDAO;从./DatasourcesEnum"导入数据源;抽象类 DAOFactory {//对于每个实体,我们都需要实现getCustomerDAO,这将使其易于替换//当另一个数据源进来时公共抽象 getCustomerDAO(): ICustomerDAO;//静态方法,根据数据源接收参数并返回特定的//工厂公共静态 getDAOFactory(whichFactory: DataSources): DAOFactory {开关(哪个工厂){案例DataSources.SharepointList:返回新的 SharepointListDAOFactory();案例数据源.JsonData:返回新的 JsonDAOFactory();默认  :返回空;}}}导出默认的 DAOFactory;从./SharepointListDAOFactory"导入 SharepointListDAOFactory;从./JsonDAOFactory"导入 JsonDAOFactory;

JsonCustomerDao.ts

从./ICustomerDao"导入ICustomerDao;从./Customer"导入客户;JsonCustomerDAO 类实现 ICustomerDao{公共插入客户():数字{//由读者完成的实现返回 1;}公共删除客户():布尔{//由读者完成的实现返回真;}公共 findCustomer(): 客户 {//由读者完成的实现返回新客户();}公共更新客户():布尔{//由读者完成的实现返回真;}公共列表客户():客户[] {//由读者完成的实现让 c1: Customer= new Customer();让 c2: Customer= new Customer();c1.id="3";c1.firstName="安德鲁";c1.lastName="瓦伦西亚";c2.id="4";c2.firstName="查尔斯";c2.lastName="史密斯";让列表:数组<客户>= [c1, c2];退货清单;}}导出默认的 JsonCustomerDAO;

SharepointCustomerDao

从./ICustomerDao"导入ICustomerDao;从./Customer"导入客户;类 SharepointCustomerDao 实现 ICustomerDao {公共插入客户():数字{//由读者完成的实现返回 1;}公共删除客户():布尔{//由读者完成的实现返回真;}公共 findCustomer(): 客户 {//由读者完成的实现返回新客户();}公共更新客户():布尔{//由读者完成的实现返回真;}公共列表客户():客户[] {//由读者完成的实现让 c1: Customer = new Customer();c1.id="1";c1.firstName="路易斯";c1.lastName="瓦伦西亚";让 c2: Customer = new Customer();c2.id="2";c2.firstName="约翰";c2.lastName="史密斯";让列表:数组<客户>= [c1, c2];退货清单;}}导出默认 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);}

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

解决方案

Reacts 在数据更改时重新渲染组件的方法是更新它的状态.

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

<代码>...使成为() {返回(<div>你好{this.state.name}</div>)}...

组件将显示 Hello 并且无论在 state.name 中

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

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

例如

<代码>...foo(receivesSomething) {const items = this.state.items;items.push(receivesSomething);this.setState({items});//一旦在任何组件中执行了 setState,react 就会在当前 DOM 和 ShadowDOM 之间产生差异,如果有所不同,则会触发受影响组件的重新渲染}...

这篇文章写得很好http://lucybain.com/blog/2017/react-js-when-to-rerender/ 并对其进行了一些解释.我建议您也研究一下一般的生命周期方法.

更新

比如这样.

class Foo 扩展了 React.Component {构造函数(道具){极好的();window.someFunction = 有效载荷 =>{//对这里的有效载荷做任何你想做的事情this.setState({items:payload});}}}

update2

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

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.

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

State

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;

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.

I found that I can use this event to set the new props datasource value when the dropdown changes

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


    this.render();

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

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?

解决方案

The Reacts way to rerender a component on data change is to updates it's state.

For instance if you have a component <Foo /> which contains a rendermethod to display it's state like

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

The component will display Hello and whetever is in the state.name

A re-render happens everythime you update the state of the given component. So in your case if you get new items, you have to push them into the state. Once that happens the react class will trigger its render method and will use the current state to display new data.

For that to work you would need a custom method which is being called from outside or within your component.

For instance

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

This article is quite nicely written http://lucybain.com/blog/2017/react-js-when-to-rerender/ and explains it a bit as well. I would recommend you to look into the lifecycle methods in general as well.

update

For instance like this.

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

If your component is listening / receiving props you can use the componentWillReceiveProps(newProps) lifecycle method from react and update your component state within that

这篇关于属性更改时如何重新渲染反应组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆