首页 > 解决方案 > Transform a SPFX TS without JS framework to a React TS

问题描述

I used yo @microsoft/sharepoint to created a webpart to display a list of items. The solution was created without Javascript framework.

import { Version } from '@microsoft/sp-core-library';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import {
  IPropertyPaneConfiguration,
  PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import { escape } from '@microsoft/sp-lodash-subset';

import styles from './GetSpListItemsWebPart.module.scss';
import * as strings from 'GetSpListItemsWebPartStrings';

import {
  SPHttpClient,
  SPHttpClientResponse   
} from '@microsoft/sp-http';
import {
  Environment,
  EnvironmentType
} from '@microsoft/sp-core-library';

export interface IGetSpListItemsWebPartProps {
  description: string;
}
export interface ISPLists {
  value: ISPList[];
}

export interface ISPList {
  ID:string;
  Title: string;
  Summary : string;
  NewsCategory: string;
  Created:string;


    AttachmentFiles:{
      Name:string;
      Url:string;
    ServerRelativeUrl: string;
    }



}

export default class GetSpListItemsWebPart extends BaseClientSideWebPart<IGetSpListItemsWebPartProps> {
  private _getListData(): Promise<ISPLists> {
    return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + "/_api/lists/GetByTitle('News')/items?$select=*&$expand=AttachmentFiles",SPHttpClient.configurations.v1)
        .then((response: SPHttpClientResponse) => {
        return response.json();
        });
    }
    private _renderListAsync(): void {

      if (Environment.type == EnvironmentType.SharePoint || 
               Environment.type == EnvironmentType.ClassicSharePoint) {
       this._getListData()
         .then((response) => {
           this._renderList(response.value);
         });
     }
   }



      public titleurl(query:string){
        var path="/Lists/News/DispForm.aspx?ID=";
        var currdir=this.context.pageContext.web.absoluteUrl;
       var result=currdir+path+query;


        return result;

      }

    private _renderList(items: ISPList[]): void {
      let html: string = '<table border=1 width=100% style="border-collapse: collapse;">';
      html += '<th>ID</th><th>Title</th> <th>Summary</th><th>Created</th><th>Attachments</th>';
      items.forEach((item: ISPList) => {
        html += `
        <tr>     
        <td>${item.ID}</td>       
            <td><a href="${this.titleurl(item.ID)}">${item.Title}</a></td>
            <td>${item.Title}</td>
            <td>${item.Created}</td>
            <td>
            <img src="${item.AttachmentFiles[0].ServerRelativeUrl}" width="300px" height="300px" />
            </td>

            </tr>
            `;
      });
      html += '</table>';

      const listContainer: Element = this.domElement.querySelector('#spListContainer');
      listContainer.innerHTML = html;
    }

  public render(): void {
    this.domElement.innerHTML = `
      <div class="${ styles.getSpListItems }">
        <div class="${ styles.container }">
          <div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${ styles.row }">
          <div class="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
          <span class="ms-font-xl ms-fontColor-white">Welcome to SharePoint Modern Developmennt</span>
          <p class="ms-font-l ms-fontColor-white">Loading from ${this.context.pageContext.web.title}</p>
          <p class="ms-font-l ms-fontColor-white">Retrive Data from SharePoint List</p>
        </div>
      </div> 
          <div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
          <div>NEWS List Items</div>
          <br>
           <div id="spListContainer" />
        </div>
      </div>`;
      this._renderListAsync();
  }

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

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          header: {
            description: strings.PropertyPaneDescription
          },
          groups: [
            {
              groupName: strings.BasicGroupName,
              groupFields: [
                PropertyPaneTextField('description', {
                  label: strings.DescriptionFieldLabel
                })
              ]
            }
          ]
        }
      ]
    };
  }
}

This part was rendered successfully.

I then created a solution yo @microsoft/sharepoint using the React option. I am stuck on how to render the HTML documents. Previous it as used to this.domElement, but it says It is not in the class. I attempted to creating another class to render seems unsuccessful. How to print the results?

import * as React from 'react';
import styles from './B.module.scss';
import { IBProps } from './IBProps';
import { escape } from '@microsoft/sp-lodash-subset';

import {
  SPHttpClient,
  SPHttpClientResponse   
} from '@microsoft/sp-http';
import {
  Environment,
  EnvironmentType
} from '@microsoft/sp-core-library';
import * as ReactDOM from 'react-dom';
export interface ISPLists {
  value: ISPList[];
}

export interface ISPList {
  ID:string;
  Title: string;
  Summary : string;
  NewsCategory: string;
  Created:string;


    AttachmentFiles:{
      Name:string;
      Url:string;
    ServerRelativeUrl: string;
    }



}



export default class B extends React.Component<IBProps, {}> {



  public render(): React.ReactElement<IBProps> {



    return (

      <div  className={ styles.b }>      
        <div id="spListContainer"></div>
        <div className={ styles.container }>
          <div className={ styles.row }>
            <div className={ styles.column }>
              <span className={ styles.title }>Welcome to SharePoint!</span>
              <p className={ styles.subTitle }>Customize SharePoint experiences using Web Parts.</p>
              <p className={ styles.description }>{escape(this.props.description)}</p>

            </div>
          </div>
        </div>
      </div>
    );
  }
}

export class shownews extends B{
  constructor(prop){
          super(prop); 

          public _getListData(): Promise<ISPLists> {
            return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + "/_api/lists/GetByTitle('News')/items?$select=*&$expand=AttachmentFiles",SPHttpClient.configurations.v1)
                .then((response: SPHttpClientResponse) => {
                return response.json();
                });
            }
            public _renderListAsync(): void {

              if (Environment.type == EnvironmentType.SharePoint || 
                       Environment.type == EnvironmentType.ClassicSharePoint) {
               this._getListData()
                 .then((response) => {
                   this._renderList(response.value);
                 });
             }
           }



              public titleurl(query:string){
                var path="/Lists/News/DispForm.aspx?ID=";
                var currdir=this.context.pageContext.web.absoluteUrl;
               var result=currdir+path+query;


                return result;

              }

            private _renderList(items: ISPList[]): void {

              let html: string = '<table border=1 width=100% style="border-collapse: collapse;">';
              html += '<th>ID</th><th>Title</th> <th>Summary</th><th>Created</th><th>Attachments</th>';
              items.forEach((item: ISPList) => {
                html += `
                <tr>     
                <td>${item.ID}</td>       
                    <td><a href="${this.titleurl(item.ID)}">${item.Title}</a></td>
                    <td>${item.Title}</td>
                    <td>${item.Created}</td>
                    <td>
                    <img src="${item.AttachmentFiles[0].ServerRelativeUrl}" width="300px" height="300px" />
                    </td>

                    </tr>
                    `;
              });
              html += '</table>';


              const listContainer = React.createElement('h1',{},html);
              ReactDOM.render(listContainer, document.getElementById('spListContainer'));
               this._renderListAsync();

            }

  }

}

I do apologize If there are many tutorials on SPFX, REACT JS on CRUD operations. However, I clone it, attempted to npm install or npm i -g, none of the repositories work for me.

2020-01-28

import * as React from 'react';
import styles from './A.module.scss';
import { IAProps } from './IAProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { PageContext } from "@microsoft/sp-page-context";
import { HttpClient, IHttpClientOptions, HttpClientResponse, SPHttpClient, ISPHttpClientOptions, SPHttpClientResponse } from '@microsoft/sp-http';

import {
  Environment,
  EnvironmentType
} from '@microsoft/sp-core-library';


export interface ISPLists {
  value: ISPList[];
};

export interface ISPList {
  ID:string;
  Title: string;
  Summary : string;
  NewsCategory: string;
  Created:string;
    AttachmentFiles:{
      Name:string;
      Url:string;
    ServerRelativeUrl: string;
    };

}


export default class A extends React.Component<IAProps, {}> {


  public test:any=[];
  public data:any=[];

  public geturl(query:string){
    var path="/Lists/News/DispForm.aspx?ID=";
    var currdir=this.props.pagecontext.web.absoluteUrl;
   var result=currdir+path+query;

    return result;

  }
  private getListData(){
    const opt: ISPHttpClientOptions = { headers: { 'Content-Type': 'application/json;odata=verbose' } };

    return this.props.SPHttpClient.get(this.props.pagecontext.web.absoluteUrl + "/_api/lists/GetByTitle('News')/items?$select=*&$expand=AttachmentFiles",SPHttpClient.configurations.v1,opt)
        .then((response: SPHttpClientResponse) => {
          response.json().then((json: any) => {


            for(let i=0;i<json.value.length;i++){
              this.data.push(<div><tr>
            <td>${json.ID}</td>
            <td><a href="${this.geturl(json.ID)}">${json.Title}</a></td>
            <td></td>
            <td>${json.Created}</td>
            <td><img src="${json.AttachmentFiles.ServerRelativeUrl}" width="300px" height="300px" /></td>
            </tr></div>);

              }
            });
          });
    }








     /*
  private renderList(item: ISPList[]): void {
         item.forEach((item: ISPList) => {
                       this.data.push(`<tr>
            <td>${item.ID}</td>
            <td><a href="${this.geturl(item.ID)}">${item.Title}</a></td>
            <td></td>
            <td>${item.Created}</td>
            <td><img src="${item.AttachmentFiles.ServerRelativeUrl}" width="300px" height="300px" /></td>
            </tr>`
                       );


                           })
                           console.log(this.data);


    };

    */
/*
    private push() {
      this.test.push(1);
      this.test.push(2);
      this.test.push(3);
      console.log(this.test);
    }
    */






  public render(): React.ReactElement<IAProps>{
    this.getListData();
    console.log(this.data);


     return (


      <div id="splist">


              TEST
        <table className={styles.container}>

          <tr>
        <th>ID</th><th>Title</th> <th>Summary</th><th>Created</th><th>Attachments</th>
        </tr>
        <tr>     
    <td></td>       
            <td><a href="${this.titleurl(item.ID)}">TITLE</a></td>
            <td></td>
            <td>Created</td>
            <td>
                 </td>

            </tr>

       {this.data} 

1234
        </table>
         </div>
    );
  }
}

2020-01-28 18:15

this.setState({ items:"<td>{item.ID}</td> 
<td>{item.Title}</td> 
<td>{item.Summary}</td> 
<td>{item.Created}</td> 
<td>{item.AttachmentFiles[0].ServerRelativeUrl}</td>" });

This do not work

this.Title.push(<span><td>{item.Title}</td></span>); 
this.Url.push(<span><td>{item.AttachmentFiles[0].ServerRelativeUrl}</td></span>); 

This Works

this.ID.push(item.ID); /* this.Title.push(<span><td>{item.Title}</td></span>); this.Url.push(<span><td>{item.AttachmentFiles[0].ServerRelativeUrl}</td></span>); */ this.forceUpdate(); 

If I use an array and use .push to send data including HTML tags the follow screenshot shows the problem. ScreenShot for using array.push(<tr><td>{item.ID}</td></tr>);

The Code

 public renderList(item: ISPList[]): void {

          item.forEach((item: ISPList) => {

          this.data.push(<tr>);
          this.data.push(<td>{item.ID}</td>);
          this.data.push(<td>{item.Title}</td>);
          this.data.push(<td>{item.AttachmentFiles[0].ServerRelativeUrl}</td>);
          this.data.push(</tr>);
//some brackets...

2020-01-28 1956 Problem TR WITHIN TR Tr within a DIV Problem: If I write the HTML tags and data in one line the tags will generate it self. But in the render method, I need to add a tag to wrap it will make my output incorrect format.

//some codes before to get the JSON data
 this.data.push(<tr>
            <td>{item.ID}</td>
            <td>{item.Title}</td>
            <td>{item.AttachmentFiles[0].ServerRelativeUrl}</td></tr>);
//some more codes

public render(): React.ReactElement<IAProps>{


     return (

      <div id="splist">

              TEST
        <table className={styles.container}>

          <tr>
            <th>ID</th>
            <th>Title</th>
          <th>Attachments</th>
          </tr>

         {this.data}

         </table>      
         </div>
    );
  }

标签: javascriptreactjstypescriptrenderspfx

解决方案


Firstly, you need to think about your solution in terms of components (having props or states) that you want to render. In context of your solution you can create a component lets say: 'GetandRenderListItems.tsx' and do all ' _getListData()' stuff. You can use 'componentDidMount()' life cycle hook to call _getListData() function everytime after the component is mounted. Then you need to write html template to render retrieved data (all what you have done in '_renderList()' method) have a look at below snippet to get an idea:

     public render(): React.ReactElement<IyourcomponentsProps> {
    return (
     // your dynamic table html and you should not use inline style but define styles in 
       scss file and use them.
    );
  }

Then in your 'yourwebpart.ts' file you can render this component in render() method:

     public render(): void {
    const element: React.ReactElement<IyourwebpartProps > = React.createElement(
      GetandRenderListItems,
      {
        description: this.properties.description,
       // similarly assign values to  other props
      }
    );

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

Hopefully this will help.

Edit

you could use array.map() e.g. To render a table using your array you could write something like that.

    public render () : React.ReactElement<IyourcomponentsProps> {
    return(
        <div className={styles.someStyle} >   
          <table className={styles.container}>
           <tr>
             <th>ID</th><th>Title</th> <th>Summary</th><th>Created</th 
             <th>Attachments</th>
           </tr>

               { yourArray.map(function(item,key){    
                  let url = this.titleurl(item.ID);
                return (<tr className={styles.rowStyle} key={key}>    //you can use key if you want to track index
         <td></td>           <td className={styles.someclass}><a href={url}>{item.Title}</a></td>    

                  </tr> ); 
              })}    

          </table>    
        </div>    


    );
}

推荐阅读