{"id":196,"date":"2019-10-12T11:43:12","date_gmt":"2019-10-12T11:43:12","guid":{"rendered":"https:\/\/raminahmadi.co.uk\/?p=196"},"modified":"2025-07-11T16:25:03","modified_gmt":"2025-07-11T16:25:03","slug":"sharepoint-framework-azure-function-and-react-hooks-where-the-magic-happens-part-2","status":"publish","type":"post","link":"https:\/\/codingwithramin.com\/?p=196","title":{"rendered":"SharePoint Framework, Azure Function and React Hooks, where the magic happens \u2013 part 2"},"content":{"rendered":"\n<p>In the previous post we developed the functions to get and apply a provisioning template using PnP core library and deployed them to the Azure Portal, then we configured the Application Registration by uploading the certificate needed for authentication process and added API permissions we need to do the operations on SharePoint.<\/p>\n\n\n\n<p>In this post we will implement the web part to call our functions and also we will learn how we can use some of the React Hooks such as useContext, useState and useEffect.<\/p>\n\n\n\n<p>I&#8217;m not going to implement the web part from scratch in this post so please download the source code from <a href=\"https:\/\/github.com\/AhmadiRamin\/react-site-provisioning-manager\">here<\/a> and continue reading.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">React Hooks<\/h2>\n\n\n\n<p>React Hooks are so magical as they make function components as powerful as class components , if you haven&#8217;t heard about them please <a href=\"https:\/\/reactjs.org\/docs\/hooks-intro.html\">read here<\/a> before go further.<\/p>\n\n\n\n<p>So let&#8217;s start with Context, as you know SPFx components start with a single parent component that splits up to many levels of child components.<\/p>\n\n\n\n<p>Imagine one of the most common issues we have in SPFx components, passing data all the way down to the last child component, and as you know data is passed up down from one component to another through props, so you have to pass data through every component by setting the props until you reach the last component!<\/p>\n\n\n\n<p>This is where&nbsp;<em><strong>Context<\/strong>&nbsp;<\/em>comes to the rescue. with React Context API you can  pass data deeply throughout your app without having to manually pass props down through multiple levels. <\/p>\n\n\n\n<p>We can create a Context in React by using React.createContext, providing the data types (as we use Typescript) and then passing in an initial value (which is null in our example below)<\/p>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"typescript\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">import * as React from 'react';\nimport { MessageBarType } from 'office-ui-fabric-react\/lib\/MessageBar';\nimport AppService from '..\/..\/..\/..\/services\/appService';\n\nexport interface IMessageBarSettings{\n    visible:boolean;\n    message: string;\n    type: MessageBarType;\n  }\n  \n  interface IAppContextInterface {\n    appService: AppService;\n    isGlobalAdmin: boolean;\n    isSiteOwner: boolean;\n    webUrl: string;\n    messageBarSettings: IMessageBarSettings;\n    isLoading:boolean;\n    toggleLoading: (visible:boolean)=>void;\n    updateMessageBarSettings: (settings:IMessageBarSettings)=>void;\n  }\n  \nconst AppContext = React.createContext&lt;IAppContextInterface | null>(null);\nexport default AppContext; \n<\/pre><\/div>\n\n\n\n<p>As you can see we have IMessageBarSettings interface that helps us to have a global message bar component as you will see later in this post as well as some global properties and methods to update some of them (when we need to display a loading image or update the message bar).<\/p>\n\n\n\n<p>Next we need to wrap our components inside the Context using the Provider which helps to pass the data through them.<\/p>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"typescript\" data-theme=\"twilight\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">import * as React from 'react';\nimport styles from '.\/App.module.scss';\nimport { IAppProps } from '.\/IAppProps';\nimport AppContext,{IMessageBarSettings} from \".\/AppContext\";\nimport { MessageBarType } from 'office-ui-fabric-react\/lib\/MessageBar';\nimport AppContent from \".\/AppContent\";\nimport * as Strings from \"SiteProvisioningWebPartWebPartStrings\";\n\nconst App: React.FC&lt;IAppProps> = (props) => {\n  const {webUrl,appService} = props;\n  const [isGlobalAdmin,setIsGlobalAdmin] = React.useState(false);\n  const [isSiteOwner,setIsSiteOwner] = React.useState(false);\n  const [isLoading,setIsLoading] = React.useState(false);\n  const [messageBarSettings,setMessageBarSettings] =React.useState({\n    message:\"\",\n    type:MessageBarType.info,\n    visible:false\n  } as IMessageBarSettings);\n  \n  \n  const updateMessageBarSettings = (settings:IMessageBarSettings)=>{\n    setMessageBarSettings(settings);\n  };\n\n  const toggleLoading = (visibleLoading:boolean)=>{\n    setIsLoading(visibleLoading);\n  };\n\n  React.useEffect(()=>{\n    let didCancel = false;\n\n    const fetchIsGloablAdmin = async ()=>{\n      const globalAdmin = await appService.checkUserIsGlobalAdmin();      \n      if (!didCancel) {\n        setIsGlobalAdmin(globalAdmin);\n      }\n      \n    };\n  \n    const fetchIsSiteOwner = async ()=>{\n      const siteOwner = await appService.IsSiteOwner();\n      if (!didCancel) {\n        setIsSiteOwner(siteOwner);\n        if(!siteOwner){\n          setMessageBarSettings({\n            message: Strings.ErrorMessageUserNotAdmin,\n            type: MessageBarType.error,\n            visible: false\n          });\n        }\n      }\n    };\n\n    fetchIsGloablAdmin();\n    fetchIsSiteOwner();\n\n    return ()=>{didCancel=true;};\n  },[]);\n\n  return (\n    &lt;div className={styles.siteProvisioningWebPart}>\n      &lt;AppContext.Provider value={{ \n        appService,\n        isGlobalAdmin,\n        isSiteOwner,\n        webUrl,\n        messageBarSettings,\n        isLoading,\n        toggleLoading,\n        updateMessageBarSettings\n        } }>\n      &lt;AppContent\/>\n      &lt;\/AppContext.Provider>\n    &lt;\/div>\n  );\n};\n\nexport default App;<\/pre><\/div>\n\n\n\n<p>As you will see, there is no class component and we use only function components as they give us many benefits, you can keep your code maintainable and readable, no setting any state and we only focus on displaying the data.<\/p>\n\n\n\n<p>AppContext.Provider has only one property called value and you need to pass the default values for the properties you defined, some of these values coming through calling a service method, this is where useEffect hook helps us to manage the side effects of a component, it servers <strong>componentDidMount<\/strong>, <strong>componentDidUpdate<\/strong> and <strong>componentWillUnmount<\/strong>&nbsp;in only one place!<\/p>\n\n\n\n<p>By default, React runs the effects after every render (including the first render), the returning method inside useEffect specify how to \u201cclean up\u201d after it&#8217;s done (it&#8217;s optional).<\/p>\n\n\n\n<p>you cannot return a Promise from useEffect.&nbsp;JavaScript async functions always return a promise and useEffect should exclusively&nbsp;<strong>return another function<\/strong>, which is used for cleaning up the effect.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Access context from child components<\/h3>\n\n\n\n<p> All we need to do to access the Context\u2019s state is import it into a component and use the useContext Hook in React! <\/p>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"typescript\" data-theme=\"twilight\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">import AppContext from \"..\/App\/AppContext\";\n\n----\n\nconst ctx = React.useContext(AppContext);<\/pre><\/div>\n\n\n\n<p>How greate is that? now you can easily get access to all values and methods of the context.<\/p>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"typescript\" data-theme=\"twilight\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">const onUploadCompleted = (response) => {\n    ctx.updateMessageBarSettings({\n        message: Strings.SuccessMessage,\n        type: MessageBarType.success,\n        visible: true\n    });\n};\n\n&lt;div hidden={ctx.isLoading}>\n    &lt;TextField disabled={!ctx.isGlobalAdmin} label=\"Site URL\" value={webUrl} onChanged={(value) => setWebUrl(value)} \/>\n    &lt;br \/>\n    &lt;FilePond disabled={!ctx.isSiteOwner} onremovefile={fileRemoved} server={\n        {\n            url: ctx.appService.applyProvisioningTemplateUrl,\n            process: {\n                        method: 'POST',\n                        ondata: (formData) => {\n                            formData.append('WebUrl', webUrl);\n                            return formData;\n                    },\n                onload: onUploadCompleted,\n                onerror: onUploadFailed\n            }\n        }\n    } \/>\n&lt;\/div><\/pre><\/div>\n\n\n\n<p>You can get a value like<strong> ctx.isSiteOwner<\/strong> or call a method like <strong>ctx.updateMessageBarSettings<\/strong> without passing them through props!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"> useState hook<\/h3>\n\n\n\n<p>Before react hooks we had to define our values in State object and call this.setState to update values, useState hook makes it easier for us to define and update values.<\/p>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"typescript\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">const [webUrl, setWebUrl] = React.useState(ctx.webUrl);\nconst [template, setTemplate] = React.useState(\"\");<\/pre><\/div>\n\n\n\n<p>useState returns a tuple where the first parameter&nbsp;is the current state of the value and second parameter is the method that will allow us to update the state. In above sample ctx.webUrl is the initial value of webUrl or template is a string value with an empty string as intial value, with setWebUrl or setTemplate methods we can update the state whenever we need it.<\/p>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"typescript\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">const response: HttpClientResponse = await ctx.appService.GetProvisioningTemplate(webUrl, handlers.join(\",\"));\nconst responseText = await response.text();\nif (response.status === 200)\n    setTemplate(responseText);<\/pre><\/div>\n\n\n\n<p>Also when you are using useState you should remember:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>We call it inside a function component to add some local state to it.<\/li><li>useState returns <strong>a pair<\/strong>: the <strong>current state value<\/strong> and a <strong>function<\/strong> that lets you<strong> update it<\/strong>. <\/li><li>It\u2019s similar to <strong>this.setState<\/strong> in a class, except it <strong>doesn\u2019t merge<\/strong> the old and new state together.<\/li><li>The only argument to useState is the <strong>initial<\/strong> state.<\/li><li>The initial state argument is only used during the first render.<\/li><li>You can use the State Hook more than once in a single component.<\/li><\/ul>\n\n\n\n<p>Hope you enjoed reading this post, you can download the source code from <a href=\"https:\/\/github.com\/AhmadiRamin\/react-site-provisioning-manager\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous post we developed the functions to get and apply a provisioning template using PnP core library and deployed them to the Azure Portal, then we configured the Application Registration by uploading the certificate needed for authentication process and added API permissions we need to do the operations on SharePoint. In this post we will implement the web part to call our functions and also we will learn how we can use some&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17,5,6,2,4,3],"tags":[9,10,18,7,11],"class_list":["post-196","post","type-post","status-publish","format-standard","hentry","category-azure-functions","category-microsoft-azure","category-microsoft-graph","category-office-365","category-sharepoint-framework","category-sharepoint-online","tag-azure","tag-azure-function","tag-react-hooks","tag-sharepoint","tag-spfx"],"_links":{"self":[{"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/posts\/196","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=196"}],"version-history":[{"count":5,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/posts\/196\/revisions"}],"predecessor-version":[{"id":269,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/posts\/196\/revisions\/269"}],"wp:attachment":[{"href":"https:\/\/codingwithramin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=196"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=196"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=196"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}