属性更改时如何重新渲染反应组件
Posted
技术标签:
【中文标题】属性更改时如何重新渲染反应组件【英文标题】:How to re-render react component when a property changes 【发布时间】:2018-11-10 02:50:38 【问题描述】:所以我有这个反应组件,它有一个下拉属性 (SPFx),它有 2 个值,我需要在更改下拉列表时再次重新呈现反应,下拉列表定义将从中检索值的数据源.
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.
状态
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);
但是视图没有重新渲染,我可以使用任何 react js 事件来重新渲染或在 prop 更改时重新设置状态吗?
【问题讨论】:
【参考方案1】:Reacts 在数据更改时重新渲染组件的方式是更新它的状态。
例如,如果您有一个组件 <Foo />
,其中包含一个渲染方法来显示它的状态
...
render()
return(
<div>Hello this.state.name</div>
)
...
组件将显示 Hello 并且无论是在 state.name 中
每次更新给定组件的状态时都会重新渲染。因此,在您的情况下,如果您获得新项目,则必须将它们推入状态。一旦发生这种情况,react 类将触发其渲染方法并使用当前状态显示新数据。
为此,您需要一个从组件外部或内部调用的自定义方法。
例如
...
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 );
更新2
如果您的组件正在侦听/接收道具,您可以使用 react 中的 componentWillReceiveProps(newProps)
生命周期方法并在其中更新您的组件状态
【讨论】:
我明白,问题是这是 Sharepoint 框架,我有一个带有一个下拉属性的 webpart,然后 webpart 有 react 组件,有一个名为 onPropertyPaneFieldChanged 的事件我可以放任何逻辑,但我如何在那里传递新状态?或者我如何触发构造函数再次执行,不确定它是否清楚我的问题。 在 javascript OOP 编程中,构造函数只在类被实例化时被调用一次。因此不能再次调用它。您可以做的是在构造函数中创建一个方法,或者在您创建全局方法的 compoentDidMount 中创建一个可以从外部访问的方法。例如window.something = () => ;并使用该方法,您会收到任何更新,然后在那里添加 setState 构造函数中的方法?不知道我是否理解这一点。 更新了我的答案。对不起,我在工作,有时不得不缩短它^^ 不确定它是否会工作 属性 'someFunction' 在类型 'Window' 上不存在。以上是关于属性更改时如何重新渲染反应组件的主要内容,如果未能解决你的问题,请参考以下文章