2017-10-17 46 views
0

J'ai l'erreur suivante:rror: FactoryMethod.render(): Un élément React valide (ou null) doit être retourné.

Error: FactoryMethod.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object. 
    at invariant (react-dom.js:17896) 

Sur mon cadre sharepoint webpart, à tout moment de la compilation est OK.

import * as React from 'react'; 
import * as ReactDom from 'react-dom'; 
import { Version } from '@microsoft/sp-core-library'; 
import { 
    BaseClientSideWebPart, 
    IPropertyPaneConfiguration, 
    PropertyPaneTextField, 
    PropertyPaneDropdown, 
    IPropertyPaneDropdownOption, 
    IPropertyPaneField, 
    PropertyPaneLabel 
} from '@microsoft/sp-webpart-base'; 

import * as strings from 'FactoryMethodWebPartStrings'; 
import FactoryMethod from './components/FactoryMethod'; 
import { IFactoryMethodProps } from './components/IFactoryMethodProps'; 
import { IFactoryMethodWebPartProps } from './IFactoryMethodWebPartProps'; 
import * as lodash from '@microsoft/sp-lodash-subset'; 
import List from './components/models/List'; 
import { Environment, EnvironmentType } from '@microsoft/sp-core-library'; 
import IDataProvider from './components/dataproviders/IDataProvider'; 
import MockDataProvider from './test/MockDataProvider'; 
import SharePointDataProvider from './components/dataproviders/SharepointDataProvider'; 

export default class FactoryMethodWebPart extends BaseClientSideWebPart<IFactoryMethodWebPartProps> { 
    private _dropdownOptions: IPropertyPaneDropdownOption[]; 
    private _selectedList: List; 
    private _disableDropdown: boolean; 
    private _dataProvider: IDataProvider; 

    protected onInit(): Promise<void> { 
    this.context.statusRenderer.displayLoadingIndicator(this.domElement, "Todo"); 

    /* 
    Create the appropriate data provider depending on where the web part is running. 
    The DEBUG flag will ensure the mock data provider is not bundled with the web part when you package the 
    solution for distribution, that is, using the --ship flag with the package-solution gulp command. 
    */ 
    if (DEBUG && Environment.type === EnvironmentType.Local) { 
     this._dataProvider = new MockDataProvider(); 
    } else { 
     this._dataProvider = new SharePointDataProvider(); 
     this._dataProvider.webPartContext = this.context; 
    } 

    this.openPropertyPane = this.openPropertyPane.bind(this); 

    /* 
    Get the list of tasks lists from the current site and populate the property pane dropdown field with the values. 
    */ 
    this.loadLists() 
     .then(() => { 
     /* 
     If a list is already selected, then we would have stored the list Id in the associated web part property. 
     So, check to see if we do have a selected list for the web part. If we do, then we set that as the selected list 
     in the property pane dropdown field. 
     */ 
     if (this.properties.spListIndex) { 
      this.setSelectedList(this.properties.spListIndex.toString()); 
      this.context.statusRenderer.clearLoadingIndicator(this.domElement); 
     } 
     }); 

    return super.onInit(); 
    } 

    //Render method of the webpart, actually calls Component 
    public render() { 

    const element: React.ReactElement<IFactoryMethodProps > = React.createElement(
     FactoryMethod, 
     { 
     spHttpClient: this.context.spHttpClient, 
     siteUrl: this.context.pageContext.web.absoluteUrl, 
     listName: this.properties.listName, 
     dataProvider: this._dataProvider 
     } 
    ); 

    ReactDom.render(element, this.domElement); 
    } 

    //Loads lists from the site and filld the dropdown 
    private loadLists(): Promise<any> { 
    return this._dataProvider.getLists() 
     .then((lists: List[]) => { 
     // Disable dropdown field if there are no results from the server. 
     this._disableDropdown = lists.length === 0; 
     if (lists.length !== 0) { 
      this._dropdownOptions = lists.map((list: List) => { 
      return { 
       key: list.Id, 
       text: list.Title 
      }; 
      }); 
     } 
     }); 
    } 

    protected get dataVersion(): Version { 
    return Version.parse('1.0'); 
    } 

    protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void { 
    /* 
    Check the property path to see which property pane feld changed. If the property path matches the dropdown, then we set that list 
    as the selected list for the web part. 
    */ 
    if (propertyPath === 'spListIndex') { 
     this.setSelectedList(newValue); 
    } 

    /* 
    Finally, tell property pane to re-render the web part. 
    This is valid for reactive property pane. 
    */ 
    super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue); 
    } 

    //Sets the selected list based on the selection from the dropdownlist 
    private setSelectedList(value: string) { 
    const selectedIndex: number = lodash.findIndex(this._dropdownOptions, 
     (item: IPropertyPaneDropdownOption) => item.key === value 
    ); 

    const selectedDropDownOption: IPropertyPaneDropdownOption = this._dropdownOptions[selectedIndex]; 

    if (selectedDropDownOption) { 
     this._selectedList = { 
     Title: selectedDropDownOption.text, 
     Id: selectedDropDownOption.key.toString() 
     }; 

     this._dataProvider.selectedList = this._selectedList; 
    } 
    } 


    //We add fields dinamycally to the property pane, in this case its only the list field which we will render 
    private getGroupFields(): IPropertyPaneField<any>[] { 
    const fields: IPropertyPaneField<any>[] = []; 

    //We add the options from the dropdownoptions variable that was populated during init to the dropdown here. 
    fields.push(PropertyPaneDropdown('spListIndex', { 
     label: "Select a list", 
     disabled: this._disableDropdown, 
     options: this._dropdownOptions 
    })); 

    /* 
    When we do not have any lists returned from the server, we disable the dropdown. If that is the case, 
    we also add a label field displaying the appropriate message. 
    */ 
    if (this._disableDropdown) { 
     fields.push(PropertyPaneLabel(null, { 
     text: 'Could not find tasks lists in your site. Create one or more tasks list and then try using the web part.' 
     })); 
    } 

    return fields; 
    } 

    private openPropertyPane(): void { 
    this.context.propertyPane.open(); 
    } 

    protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { 
    return { 
     pages: [ 
     { 
      header: { 
      description: strings.PropertyPaneDescription 
      }, 
      groups: [ 
      { 
       groupName: strings.BasicGroupName, 
       /* 
       Instead of creating the fields here, we call a method that will return the set of property fields to render. 
       */ 
       groupFields: this.getGroupFields() 
      } 
      ] 
     } 
     ] 
    }; 
    } 
} 


//#region Imports 
import * as React from 'react'; 
import styles from './FactoryMethod.module.scss'; 
import { IFactoryMethodProps } from './IFactoryMethodProps'; 
import { 
    IDetailsListItemState, 
    IDetailsNewsListItemState, 
    IDetailsDirectoryListItemState, 
    IDetailsAnnouncementListItemState, 
    IFactoryMethodState 
} from './IFactoryMethodState'; 
import { IListItem } from './models/IListItem'; 
import { IAnnouncementListItem } from './models/IAnnouncementListItem'; 
import { INewsListItem } from './models/INewsListItem'; 
import { IDirectoryListItem } from './models/IDirectoryListItem'; 
import { escape } from '@microsoft/sp-lodash-subset'; 
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http'; 
import { ListItemFactory} from './ListItemFactory'; 
import { TextField } from 'office-ui-fabric-react/lib/TextField'; 
import { 
    DetailsList, 
    DetailsListLayoutMode, 
    Selection, 
    IColumn 
} from 'office-ui-fabric-react/lib/DetailsList'; 
import { MarqueeSelection } from 'office-ui-fabric-react/lib/MarqueeSelection'; 
import { autobind } from 'office-ui-fabric-react/lib/Utilities'; 
//#endregion 

export default class FactoryMethod extends React.Component<IFactoryMethodProps, IFactoryMethodState> { 
    private listItemEntityTypeName: string = undefined; 
    private _selection: Selection; 

    constructor(props: IFactoryMethodProps, state: any) { 
    super(props); 
    this.setInitialState(); 
    } 

    public componentWillReceiveProps(nextProps: IFactoryMethodProps) { 
    this.listItemEntityTypeName = undefined; 
    this.setInitialState(); 
    } 

    public setInitialState(): void { 
    this.state = { 
     type: 'ListItem', 
     status: this.listNotConfigured(this.props) 
     ? 'Please configure list in Web Part properties' 
     : 'Ready', 
     DetailsListItemState:{ 
     columns:[], 
     items:[] 
     }, 
     DetailsNewsListItemState:{ 
     columns:[], 
     items:[] 
     }, 
     DetailsDirectoryListItemState:{ 
     columns:[], 
     items:[] 
     }, 
     DetailsAnnouncementListItemState:{ 
     columns:[], 
     items:[] 
     }, 
    }; 
    } 

    //Reusable inline component 
    public ListMarqueeSelection = (itemState: {columns: IColumn[], items: IListItem[] }) => (
     <div> 
     <MarqueeSelection selection={ this._selection }> 
      <DetailsList 
      items={ itemState.items } 
      columns={ itemState.columns } 
      setKey='set' 
      layoutMode={ DetailsListLayoutMode.fixedColumns } 
      selection={ this._selection } 
      selectionPreservedOnEmptyClick={ true }     
      compact={ true }> 
      </DetailsList> 
     </MarqueeSelection> 
     </div> 
) 

    public render(): React.ReactElement<IFactoryMethodProps> { 
    let { type, 
     status, 
     DetailsListItemState, 
     DetailsNewsListItemState, 
     DetailsDirectoryListItemState, 
     DetailsAnnouncementListItemState } = this.state; 

     switch(this.props.listName) 
     { 
      case "List": 
      return <this.ListMarqueeSelection items={this.state.DetailsListItemState.items} columns={this.state.DetailsListItemState.columns} />; 
      case "News": 
      return <this.ListMarqueeSelection items={this.state.DetailsNewsListItemState.items} columns={this.state.DetailsNewsListItemState.columns}/>; 
      case "Announcements": 
      return <this.ListMarqueeSelection items={this.state.DetailsAnnouncementListItemState.items} columns={this.state.DetailsAnnouncementListItemState.columns}/>; 
      case "Directory": 
      return <this.ListMarqueeSelection items={this.state.DetailsDirectoryListItemState.items} columns={this.state.DetailsDirectoryListItemState.columns}/>; 
      default: 
      return undefined; 
     } 
    } 

    //Read items using factory method pattern and sets state accordingly 
    private readItems(): void { 
    this.setState({ 
     status: 'Loading all items...' 
    }); 

    this.setStateWithList();  
    } 

    private setStateWithList(): void { 
    const factory = new ListItemFactory(); 
    const items = factory.getItems(this.props.spHttpClient, 
    this.props.siteUrl, this.props.listName); 
    const keyPart = this.props.listName === 'Items' ? '' : this.props.listName;  

    // the explicit specification of the type argument `keyof {}` is bad and 
    // it should not be required. 
    this.setState<keyof {}>({ 
     status: `Successfully loaded ${items.length} items`, 
     ['Details' + keyPart + 'ListItemState'] : { 
      items, 
      columns: [ 
      ] 
     } 
     });  
    } 

    //Gets the selected item details 
    private getSelectionDetails(): string { 
    let selectionCount = this._selection.getSelectedCount(); 

    switch (selectionCount) { 
     case 0: 
     return 'No items selected'; 
     case 1: 
     return '1 item selected: ' + (this._selection.getSelection()[0] as any).name; 
     default: 
     return `${selectionCount} items selected`; 
    } 
    } 

    private listNotConfigured(props: IFactoryMethodProps): boolean { 
    return props.listName === undefined || 
     props.listName === null || 
     props.listName.length === 0; 
    } 

} 

Répondre

0

erreur lol est explicite, l'attention de na pas assez payer

switch(this.props.listName) 
     { 
      case "List": 
      return <this.ListMarqueeSelection items={this.state.DetailsListItemState.items} columns={this.state.DetailsListItemState.columns} />; 
      case "News": 
      return <this.ListMarqueeSelection items={this.state.DetailsNewsListItemState.items} columns={this.state.DetailsNewsListItemState.columns}/>; 
      case "Announcements": 
      return <this.ListMarqueeSelection items={this.state.DetailsAnnouncementListItemState.items} columns={this.state.DetailsAnnouncementListItemState.columns}/>; 
      case "Directory": 
      return <this.ListMarqueeSelection items={this.state.DetailsDirectoryListItemState.items} columns={this.state.DetailsDirectoryListItemState.columns}/>; 
      default: 
      return null; 
     } 

changé est revenu non défini pour retourner null