Matthias
Matthias

Reputation: 29

How to transform a class component to a functional component in SPFx React.js and get value from a SharePoint list

I have a written a class component in SPFx with the pnp/js framework and React.js. I need to transform it to a functional component in react. I'm struggeling to call my SharePoint lists now. I have a SharePoint DataProvider.ts and a pnpConfig.ts

Here ist my code so far: SharePoint DataProvider.ts

import {getSP} from '../PNPConfig/pnpConfig';
import {SPFI} from "@pnp/sp";
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { IMedEvalListItem } from 
                   '../spFxReactFuncFragebogen/components/IMedEvalListItemDefinition';}



  export default class SharePointDataProvider{

     private _sp: SPFI;

   constructor(wpContext: WebPartContext){
      this._sp=getSP(wpContext);
    
}

public GetSPObject(): SPFI {
   return this._sp;
}

public GetLists = async (): Promise<IMedEvalListItem[]> => {
    try{
       const response: IMedEvalListItem[] =await 
        this._sp.web.lists.select("Title","Id").filter("Hidden eq false")();
       return response;
      }
      catch(e){
        return e;
      }
     }
     }

PNP Config:

 import { WebPartContext } from "@microsoft/sp-webpart-base";

 import {spfi, SPFI, SPFx} from "@pnp/sp";
 import {LogLevel, PnPLogging} from "@pnp/logging";
 import "@pnp/sp/webs";
 import "@pnp/sp/lists";
 import "@pnp/sp/items";
  import "@pnp/sp/batching";


export const getSP= (context:WebPartContext): SPFI =>{
 return spfi().using(SPFx(context as 
  WebPartContext)).using(PnPLogging(LogLevel.Warning));
 };

My function component:

 import * as React from 'react';
  //import styles from './SpFxReactFuncFragebogen.module.scss';
 import type { ISpFxReactFuncFragebogenProps } from './ISpFxReactFuncFragebogenProps';
 import { IMedEvalListItem } from './IMedEvalListItemDefinition';
 import SharePointDataProvider from '../../DataProvider/SharePointDataProvider';


    export default function 
SpFxReactFuncFragebogen(props:ISpFxReactFuncFragebogenProps):React.ReactElement<ISpFxReactFuncFragebogenProps> {



    const[medItems,setMedItems]=React.useState<[IMedEvalListItem]>();

 const spService= new SharePointDataProvider(this.context);



 React.useEffect(() => {
  fetchListItems();
  }, []);


const fetchListItems = async () => {
  try {
    const items = await spService.GetLists();
    setMedItems(items);
  } catch (error) {
    console.error('Error fetching list items:', error);
  }
};
  

return (
  <section>
      <div>
        {medItems}
           
      </div>
  </section>
  
);
}

I'm not sure where my errors are. I need to know if I can call SharePoint like this and how I get the values in the useState Variable.

Best regards

Matthias

Upvotes: 1

Views: 304

Answers (1)

Rob Windsor
Rob Windsor

Reputation: 6859

Take a look at this blog post that shows how to convert a SPFx class component into a functional component. It includes an example of getting data from SharePoint using the REST API and render it in the web part.

How to use React Hooks with the SharePoint Framework (SPFx)

import * as React from 'react';
import { useState } from 'react';
import { useState, useEffect } from 'react';
import styles from './SpFxReactHooks.module.scss';
import { ISpFxReactHooksProps } from './ISpFxReactHooksProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';

const SpFxReactHooks: React.FC<ISpFxReactHooksProps> = (props) => {
  const {
    hasTeamsContext,
    userDisplayName,
    // update prop interface & add as input prop in web part (not shown)
    spHttpClient
  } = props;

  const [counter, setCounter] = useState<number>(1);
  const [evenOdd, setEvenOdd] = useState<string>('');
  const [siteLists, setSiteLists] = useState<string[]>([]);

  useEffect(() => {
    (async () => {
      // line wrapping added for readability
      const endpoint: string = `${currentSiteUrl}/_api/web/lists
                        ?$select=Title
                        &$filter=Hidden eq false
                        &$orderby=Title
                        &$top=10`;
      const rawResponse: SPHttpClientResponse = await spHttpClient.get(
                                   endpoint, SPHttpClient.configurations.v1);
      setSiteLists(
        (await rawResponse.json()).value.map((list: { Title: string }) => {
          return list.Title;
        })
      );
    })();
  }, []);

  useEffect(() => {
    setEvenOdd((counter % 2 === 0) ? 'even' : 'odd');
  }, [counter]);

  const onButtonClick = (): void => {
    setCounter(counter + 1);
  }

  return (
    <section className={`${styles.SpFxReactHooks} ${hasTeamsContext ? styles.teams : ''}`}>
      <div className={styles.welcome}>
        <h2>Well done, {escape(userDisplayName)}!</h2>
        <div>Counter: <strong>{counter}</strong> is <strong>{evenOdd}</strong></div>
        <button onClick={() => onButtonClick()}>+</button>
        <ul>
        {
          siteLists.map((list: string) => (
            <li>{list}</li>
          ))
        }
        </ul>
      </div>
    </section>
  );
}

export default SpFxReactHooks;

Upvotes: 0

Related Questions