Ana Sayfa Blog

SharePoint job timer config (OWSTIMER.EXE.CONFIG) dosyası nerede tutulur?

0

SharePoint (on premise) job timer config dosyası aşağıdaki lokal yolda bulunmaktadır:

C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\BIN\OWSTIMER.EXE.CONFIG

SharePoint sürümüne bağlı olarak ..\15\.. 14,15, 16 olabilir.

PowerShell kullanarak SharePoint farm içerisindeki sunucularda IISRESET işlemi

0

SharePoint farm içerisinde yer alan tüm sunucularda IISRESET işlemini gerçekleştirmek için aşağıdaki kodu kullanabilirsiniz.

Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
#Get All SharePoint Servers - Except DB and SMTP Servers
$Servers = Get-SPServer | Where {$_.Role -ne "Invalid" }
#Iterate through the list and restart one by one.
foreach ($server in $servers) 
{ 
Write-Host "Restarting IIS on server: $($Server.Name)"
IISRESET $Server.Address
#Optional: Get the Status
Write-Host "IIS status for server $($server):" 
IISRESET $server.Address /status
}
Write-host "IIS Restarted on All Servers of the Farm!" -f Green 

PowerShell kullanılarak SharePoint Server cache temizleme

0

Aşağıdaki Powershell kodunu kullanarak farm içerisinde yer alan sunucularda cache temizleyebilirsiniz.

Add-PSSnapin -Name Microsoft.SharePoint.PowerShell –erroraction SilentlyContinue
write-host "CLEAR CONFIG CACHE ON FARM" -fore green
$servers = get-spserver | ?{$_.role -ne "Invalid"}
foreach ($server in $servers)
{
$servername = $server.Address
write-host "Stop Timer Service on server $servername" -fore yellow
(Get-WmiObject Win32_Service -filter "name='SPTimerV4'" -ComputerName $servername).stopservice() | Out-Null
}
foreach ($server in $servers)
{
$servername = $server.Address
$folders = Get-ChildItem ("\\" + $servername + "\C$\ProgramData\Microsoft\SharePoint\Config")
foreach ($folder in $folders)
{
$items = Get-ChildItem $folder.FullName -Recurse
foreach ($item in $items)
{
if ($item.Name.ToLower() -eq “cache.ini”)
{
$cachefolder = $folder.FullName
}
}
}
write-host "Found CacheFolder on Server $servername = $cachefolder" -fore Yellow
$cachefolderitems = Get-ChildItem $cachefolder -Recurse
write-host "Delete all XMQL Files inside this CacheFolder" -fore Yellow
foreach ($cachefolderitem in $cachefolderitems)
{
if ($cachefolderitem -like “*.xml”)
{
$cachefolderitem.Delete()
}
}
$a = Get-Content $cachefolder\cache.ini
$a = 1
write-host "Creating a new Cache.ini File on server $servername" -fore Yellow
Set-Content $a -Path $cachefolder\cache.ini
}
foreach ($server in $servers)
{
$servername = $server.Address
write-host "START Timer Service on server $servername" -fore yellow
(Get-WmiObject Win32_Service -filter "name='SPTimerV4'" -ComputerName $servername).startservice() | Out-Null
}

SharePoint 2013 – CSOM için Dosya Yükleme Limitini 2 Mb’dan 10 Mb’a Yükseltme

0

CSOM geliştirdiğiniz bir uygulamanız olduğunu düşünelim, stream etmiş olduğunuz bir dosyanız mevcut ve Document Library içerisine upload etmek istediğinizde dosya boyutunuz 2 MB’den daha fazla dosya ise hata veriyor olacaktır.

The request message is too large. The server does not allow messages that are larger than 2097152 bytes.

Buradaki limiti arttırmak isterseniz aşağıdaki PowerShell kodunu kullanmanız yeterli olacaktır. (10 MB = 10*1024*2014)

$ws = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$ws.ClientRequestServiceSettings.MaxReceivedMessageSize = 10485760‬
$ws.ClientRequestServiceSettings.MaxParseMessageSize  = 10485760‬
$ws.Update()

Not: Sadece ilgili sunucuda gerekli olan dosya transfer boyutu arttırmaktadır. Bu yüzden bir farm yapınız mevcut ise diğer sunucularda da arttırım yapmanız gerekmektedir.

Microsoft Graph API ile SharePoint İçerisindeki Dosya ya da Sayfa Önizlemesi Alma

0

SharePoint içerisinde yer alan dosya ya da modern arayüzdeki sayfaların thumnail resimleri OneDrive içerisinde tutulmaktadır.

Flow ya da SPFx ile geliştirme yaparken ilgili thumnail ‘a erişim sağlamak için MS Graph API tercih edebilirsiniz. https://docs.microsoft.com/en-us/graph/api/driveitem-list-thumbnails

Modern Design ile site kurulumu yaptıysanız SharePoint ‘in default News WebPart ‘ının aynı yapıyı kullanmakta olduğunu görüyor olacaksınız.

https://tenantname.sharepoint.com/_api/v2.1/sites/tenantname.sharepoint.com,e7d61826-2450-48c8-9c5f-c6ac0cc6f6f0,cc00737f-fb58-4259-a2a7-a26aa01b9737/items/0f5cdb4c-e4f9-4105-b722-abb5732f56b6/driveItem/thumbnails/0/c400x99999/content?preferNoRedirect=true&clientType=modernWebPart

Yukarıda direkt olarak Microsoft Graph endpoint mevcut değildir. Endpoint olarak v2 versiyonu üzerinden gerekli request gönderimi sağlanmıştır. İhtiyacınıza göre v1 versiyonunu da kullanabilirsiniz.

V1: https://docs.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0

V2: https://docs.microsoft.com/en-us/sharepoint/dev/apis/sharepoint-rest-graph

Aşağıda ilgili API ‘nin istediği parametrelere göre değerleri tanımlamanız durumunda thumnail ‘e ulaşabilmektesiniz.

<endpoint>/sites/<site id>/lists/<list id>/items/<item id>/driveItem/thumbnails/0/<custom size>/content

Site ID, sitenin object id GUID
List ID, listenin object id GUID
Item ID, itemın object id Integer/GUID
Custom Size, thumnail için resim boyutu tanımlamanıza olanak sağlamaktadır. (https://docs.microsoft.com/en-us/graph/api/driveitem-list-thumbnails?view=graph-rest-1.0&tabs=http#requesting-custom-thumbnail-sizes)

Ek olarak, tek yöntem yukarıdaki API değildir. Modern Page ‘e Rest API erişim sağladığınızda Banner Image URL field ‘ı ile thumnail resmine erişim sağlanız mümkün.

sites/KaizalaDemo/_layouts/15/getpreview.ashx?guidSite=e7d61826245048c89c5fc6ac0cc6f6f0&guidWeb=cc00737ffb584259a2a7a26aa01b9737&guidFile=272b0a2a11204f9faf9805b9e74c7150&ext=jpeg

Okuduğunuz içi teşekkür ederim. 🙂

SharePoint Framework (SPFx) – Library Component

0

Bir önceki makalemde SharePoint Framework (SPFx) v1.9.1 ile SharePoint Library Component ‘in release olduğundan bahsetmiştim. Peki SharePoint Library Component nedir? Şimdi buna bir göz atalım.

Sorun

SharePoint Library anlatmadan önce sorun tam olarak neydi? Hemen ona değineyim. Şimdi aşağıdaki gibi page içerisinde 2 tane WebPart ‘ımızın olduğunu ve her iki WebPart içerisinde “jquery” kullandığımızı düşünelim.

Bu kısımda gulp-bundle ederken her iki WebPart ‘ın kullanmış olduğu “jquery” ‘yi ekler. (WebPart bazında izole olması için) Custom kendi library ‘lerinizi yönetmek bu durumda daha zorlaşmakta ve istemediğimiz yani daha çok uğraştırıcı bir yönteme doğru geçişimizin başlamasına sebep oluyor.

hello-world-web-part.js
hello-world-web-part2.js

Bu durum hem sayfanın yavaşlamasına hem de tekrar eden kod bloklarına sebep olmaktadır.

SPFx Library Component Oluşturma

SharePoint Library kullanmadan CDN üzerindende tüm işlemlerimizi yapabiliriz fakat gereksiz efor oluşturacağı için artık yeni yöntem üzerinden ilerlemekte fayda olduğunu düşünüyorum.

  • İlk olarak projesinizi oluşturmak istediğiniz lokasyona gidiniz ve library component ‘inizi oluşturacağınız klasörü oluşturunuz.
md corporate-library
  • Aşağıdaki komut ile oluşturmuş olduğunuz klasör ‘e gidiniz.
cd corporate-library
  • Yeoman SharePoint Generator çalıştırmak için aşağıdaki komutu çalıştırınız.
yo @microsoft/sharepoint
  1. What is your solution name?” default olarak “example-library” yazmaktadır, “enter” tuşuna basıp kullanabilir ya da farklı bir solution name belirtebilirsiniz.
  2. Which baseline packages do you want to target for your component(s)? (Use arrow keys)” son versiyon üzerinden devam ediniz.
  3. Where do you want to place the files? (Use arrow keys)” oluşturulacak dosyaların hangi kısma atılmasını belirtiniz. “Use the current folder” deyip, var olan klasör üzerine oluşturmayı tercih ediniz.
  4. Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites? (y/N)” tüm sitelerde otomatik olarak dağıtılmış bir şekilde kullanmak gerektiği için, “y” deyip, “enter” tuşuna basınız.
  5. Which type of client-side component to create? (Use arrow keys)” client -side component olarak seçiminizi “Library” olarak yapınız.
  • Sonraki parametreler library component için gerekli bilgilerdir:
  1. “Add new Library to solution?” Library ismini yazınız.
  2. What is your Library description?” Library için açıklama giriniz.

Tüm parametrelerimizi girdikten sonra projeniz oluşacaktır.

Library için gerekli adımlarımızı tamamladık, şimdi local ve deploy sonrası neler yapmamız gerekiyor adım adım ilerleyelim.

Lokaliniz İçerisinde SPFx Library Nasıl Kullanılır?

  • İlk olarak library oluşturduğunuz solution rool folder içerisine gidip aşağıdaki komutu çalıştırınız.
npm link

Bu sayede lokalimizde diğer projelerimizde kullanmak üzere npm link ile hazırlamış olduk.

  • Ardından kullanmak istediğiniz diğer projenin rool folder ‘ına gidip aşağıdaki scripti çalıştırınız.
npm link example-library
  • WebPart içerisine artık library import edebiliriz.
import * as ExampleLibrary from 'example-library';
  • Örnek olması adına kodun tamamını paylaşıyorum.
import * as React from 'react';
import styles from './HelloWorld.module.scss';
import { IHelloWorldProps } from './IHelloWorldProps';
import { escape } from '@microsoft/sp-lodash-subset';
import * as ExampleLibrary from 'example-library';

export default class HelloWorld extends React.Component<IHelloWorldProps, {}> {
  public render(): React.ReactElement<IHelloWorldProps> {
    var myInstance = new ExampleLibrary.ExampleLibraryLibrary();
  
  return(
      <div className = { styles.helloWorld } >
      <div className={styles.container}>
        <div className={styles.row}>
          <div className={styles.column}>
            <span className={styles.title}>Welcome to SharePoint!</span>
            <p className={styles.subTitle}>{myInstance.name()}</p>
            <p className={styles.description}>{escape(this.props.description)}</p>
            <a href="https://aka.ms/spfx" className={styles.button}>
              <span className={styles.label}>Learn more</span>
            </a>
          </div>
        </div>
      </div>
      </div>
    );
  }
}

“gulp serve” dediğinizde library içerisine yer alan “name” function değerini döndürmektedir.

SPFx Library Deploy ve Kullanımı

  • İlk olarak library solution içerisinde aşağıdaki kodu çalıştırarak paketi hazırlayalım.
gulp bundle --ship
gulp package-solution --ship
  • App catalog içerisine paketimizi upload ederek “Make this solution available to all sites in the organization” checkbox işaretleyelim. Bu sayede tüm sitelere yükleme işlemlerimizi yaptığımız için diğer projeler içerisinde kullanabilmekteyiz.
  • Library ile ilgili işlemlerimizi tamamladıktan sonra WebPart solution içerisinde yer alan “package.json” açınız ve “dependencies” kısmına aşağıdaki gibi library solution ekleyiniz.
"dependencies": {
    "example-library": "0.0.1",
    "@microsoft/sp-core-library": "1.9.0",
    "@types/webpack-env": "1.13.1",
    "@types/es6-promise": "0.0.33"
},
  • Son olarak WebPart için aşağıdaki kodu kullanarak paketleyip, app catalog içerisine yükleyiniz.
gulp bundle --ship
gulp package-solution --ship

Sonuç

Library component hayatımızı çok kolaylaştırmaktadır fakat bazı dikkat edilmesi gereken husus bulunmaktadır:

  • Library içerisinde güncelleme yaptığınızda diğer projelerinizde library kullanıldığı için daha dikkat etmeniz gerekmektedir. Aksi taktirde deploy işleminden sonra bazı modülleriniz üzerinde çalışmama gibi sorunlar yaşanabilir. Bu yüzden dikkat etmeniz gerekmektedir.
  • Bazı modülleriniz için versiyon bazında farklılar olabilir. Yani x modülünüz y.v1 versiyonu ile çalışırken, z modülünüz y.v2 projesi ile çalışması gerekebilir. Bu durum ise tek versiyon çıkmanızdan kaynaklanmaktadır. Bu durumda “[email protected]” gibi bir çözüme başvurabilirsiniz.

Kısacası, Library component bir çok konuda işlemimizi kolaylaştırmaktadır. Sayfa içerisinde çok sayıda WebPart ‘ınız mevcut ise, library component olarak güncellemeniz performans ve response time olarak fark ediyor olacaktır.

Okuduğunuz için teşekkür ederim. 🙂

Office CLI ile SharePoint Framework Upgrade

0

SharePoint Framework (SPFx) projelerimizde library, React Hooks gibi özelliklere erişmek için SharePoint Framework upgrade etmemiz gerekmektedir. Yine çoğu zaman olduğu gibi PnP ekibi devreye giriyor. 🙂 Bu konuda işimizi baya kolaylaştırıyorlar. Çok kısa zaman önce v2 ile artık daha iyi hale gelen Office CLI kullanarak var olan projenizde upgrade işleminizi gerçekleştirmeniz daha sağlıklı olacaktır. Sebebi ise manuel olarak yapacağınız adımları listeyip, yapılması gerekenleri yönlendirmektedir.

Şimdi nasıl kullanacağımıza değinelim. İlk olarak Office CLI bilgisayarınızda kurulu değilse, aşağıdaki komutu kullanarak kurmanız gerekmektedir.

Kurulum

npm kullanıyorsanız:

npm i -g @pnp/office365-cli

yarn kullanıyorsanız:

yarn global add @pnp/office365-cli

Upgrade İşlemlerine Başlayalım

  • Command Prompt ile projenizin olduğu lokasyona gidiniz.
  • Sonrasında o365  ile upgrade işlemi ile ilgili kodu çalıştırmanız gerekmektedir. Upgrade ile ilgili detaylı parametreler için linke tıklayınız.
o365 spfx project upgrade --output md > report.md

Scripti çalıştırdıktan sonra report.md dosyasına gerekli adımları çıkartıyor olacaktır. Örnek bir ekran çıktısını aşağıya ekliyorum.

# Upgrade project c:\Examples\vue-js-org-chart to v1.9.1

Date: 9/12/2019

## Findings

Following is the list of steps required to upgrade your project to SharePoint Framework version 1.9.1. [Summary](#Summary) of the modifications is included at the end of the report.

### FN001001 @microsoft/sp-core-library | Required

Upgrade SharePoint Framework dependency package @microsoft/sp-core-library

Execute the following command:

```sh
npm i -SE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN001002 @microsoft/sp-lodash-subset | Required

Upgrade SharePoint Framework dependency package @microsoft/sp-lodash-subset

Execute the following command:

```sh
npm i -SE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN001003 @microsoft/sp-office-ui-fabric-core | Required

Upgrade SharePoint Framework dependency package @microsoft/sp-office-ui-fabric-core

Execute the following command:

```sh
npm i -SE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN001004 @microsoft/sp-webpart-base | Required

Upgrade SharePoint Framework dependency package @microsoft/sp-webpart-base

Execute the following command:

```sh
npm i -SE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN001021 @microsoft/sp-property-pane | Required

Upgrade SharePoint Framework dependency package @microsoft/sp-property-pane

Execute the following command:

```sh
npm i -SE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN002001 @microsoft/sp-build-web | Required

Upgrade SharePoint Framework dev dependency package @microsoft/sp-build-web

Execute the following command:

```sh
npm i -DE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN002002 @microsoft/sp-module-interfaces | Required

Upgrade SharePoint Framework dev dependency package @microsoft/sp-module-interfaces

Execute the following command:

```sh
npm i -DE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN002003 @microsoft/sp-webpart-workbench | Required

Upgrade SharePoint Framework dev dependency package @microsoft/sp-webpart-workbench

Execute the following command:

```sh
npm i -DE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN002009 @microsoft/sp-tslint-rules | Required

Upgrade SharePoint Framework dev dependency package @microsoft/sp-tslint-rules

Execute the following command:

```sh
npm i -DE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN002011 @microsoft/rush-stack-compiler-2.9 | Required

Install SharePoint Framework dev dependency package @microsoft/rush-stack-compiler-2.9

Execute the following command:

```sh
npm i -DE @microsoft/[email protected]
```

File: [./package.json](./package.json)

### FN010001 .yo-rc.json version | Recommended

Update version in .yo-rc.json

In file [./.yo-rc.json](./.yo-rc.json) update the code as follows:

```json
{
  "@microsoft/generator-sharepoint": {
    "version": "1.9.1"
  }
}
```

File: [./.yo-rc.json](./.yo-rc.json)

### FN021001 main | Required

Add package.json property

In file [./package.json](./package.json) update the code as follows:

```json
{
  "main": "lib/index.js"
}
```

File: [./package.json](./package.json)

### FN012017 tsconfig.json extends property | Required

Update tsconfig.json extends property

In file [./tsconfig.json](./tsconfig.json) update the code as follows:

```json
{
  "extends": "./node_modules/@microsoft/rush-stack-compiler-2.9/includes/tsconfig-web.json"
}
```

File: [./tsconfig.json](./tsconfig.json)

### FN017001 Run npm dedupe | Optional

If, after upgrading npm packages, when building the project you have errors similar to: "error TS2345: Argument of type 'SPHttpClientConfiguration' is not assignable to parameter of type 'SPHttpClientConfiguration'", try running 'npm dedupe' to cleanup npm packages.

Execute the following command:

```sh
npm dedupe
```

File: [./package.json](./package.json)

## Summary

### Execute script

```sh
npm i -SE @microsoft/[email protected] @microsoft/[email protected] @microsoft/[email protected] @microsoft/s[email protected] @microsoft/[email protected]
npm i -DE @microsoft/[email protected] @microsoft/[email protected] @microsoft/[email protected] @microsoft/[email protected] @microsoft/[email protected]
```

### Modify files

#### [./.yo-rc.json](./.yo-rc.json)

Update version in .yo-rc.json:

```json
{
  "@microsoft/generator-sharepoint": {
    "version": "1.9.1"
  }
}
```

#### [./package.json](./package.json)

Add package.json property:

```json
{
  "main": "lib/index.js"
}
```

#### [./tsconfig.json](./tsconfig.json)

Update tsconfig.json extends property:

```json
{
  "extends": "./node_modules/@microsoft/rush-stack-compiler-2.9/includes/tsconfig-web.json"
}
```
  • Bu çıktıyı elde ettikten sonra “## Summary” kısmında yer alan “### Execute script” çalıştırınız.
  • İşleminizi tamamladıktan sonra “### Modify files” başlığında yer alan adımları tamamlayınız.
  • Son olarak yapılması gereken başka adımların mevcut olup olmadığını kontrol etmek amacıyla upgrade scriptini tekrar çalıştırınız.
o365 spfx project upgrade --output md > report.md
  • “Project doesn’t need to be upgraded” yapılacak herhangi bir adım kalmadığına emin olduktan sonra, tüm işlemler tamamlanmıştır.

Okuduğunuz için teşekkür ederim. 🙂

SharePoint – PowerShell ile User Profile Picture Senkronizasyonu

0

SharePoint 2016 ve SharePoint 2019 ‘da maalesef kullanıcıların resimleri düzgün bir şekilde aktarılamamaktadır. Bu durum içinde Microsoft Identity Manager kurulması ve konfigürasyon işleminin yapılmasına ihtiyaç duyulmaktadır. Bu da ek maliyet ve efora sebep olmaktadır. AD içerisindeki resimleri SharePoint ‘e aktarmak için aşağıdaki scripti download ederek kullanmaya başlayabilirsiniz.

Scripti çalıştırmadan önce User Profile Service tarafında AD connection tanımlanması, MySite konfigüre edilmiş olması ve sync işleminin başlatılarak profillerin yüklenmesi gerekmektedir.

Yukarıdaki scripti indirdikten sonra aşağıdaki kısımları kendi ihtiyacınıza göre güncelleyip, kullanmaya başlayabilirsiniz.

Script içerisinde “User Photos/Profile Pictures” klasörüne resimleri oluşturmaktadır. Türkçe olarak açılan site ‘larda “Profile Pictures” ibaresini “Profil Resimleri” olarak değiştiriniz.

$Location = "C:\Dirsync\"
#First time running, just run "DirSync" then "UploadPicture $adusers"
#Update RootDSE to match your domain
$RootDSE = [ADSI]"LDAP://dc=contoso,dc=com"
$site	  = Get-SpSite http://MySiteHostURL
$domain = "domain\"
#This is for domains that may not resolve the short name.  We can have a domain controller, FQDN, or shortname for the domain.
$DCorDomainName = "Contoso.com"
#This will write the pictures to the folder specified in $location
$write2disk = $false
#LDAP filter that is currently set to pull in users with thumbnailphoto and not disabled users.
$LDAPFilter = "(&(objectCategory=person)(objectclass=user)(thumbnailphoto=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"
#Set $UseDifferentSvcAccount to true to be prompted for a different service account.  False will use the user that is running the script to connect to AD.
$UseDifferentSvcAccount = $false

Kaynakça: https://gallery.technet.microsoft.com/office/SharePoint-User-Profile-928b39c0

SharePoint Framework (SPFx) v1.9.1 Güncellemesi Neler İçermektedir?

0

SharePoint Framework 1.9.0 release olmuştu fakat bazı sorunlarından dolayı geri alınmıştı ve beklenen 1.9.1 güncellemesi yayınlandı. Linke tıklayarak detaylı release notlarına erişebilirsiniz.

Neler değişti?

  • Library component, genel olarak kullanıma sunuldu. Artık preview değil 🙂
  • Webpack 3 ‘ten Webpack 4 ‘e geçiş yapıldı. Daha hızlı build elde edebilmekteyiz.
  • Teams SDK Vanity URLs destekleyen 1.4.2 versiyonuna yükseltildi.
  • GraphHttpClient kaldırıldı. Onun yerine MSGraphClient sınıfını kullanmanız gerekmektedir.
  • SPHttpClientBatch son versiyonu sunuldu. Bu sayede tüm request ‘lerinizi topluca gerçekleştirebilirsiniz.
  • Office Fabric v6.189.2 support vermeye başladı.
  • TypeScript v3.5.3 versiyonuna support vermeye başladı.
  • React support verilen versiyon v16.8 yükseltildi. React Hooks artık kullanabiliyoruz 🙂 React Hooks ile ilgili detaylı bilgi için linke tıklayınız.

React Hooks ile ilgili hemen bir kod örneği paylaşayım 🙂

import * as React from 'react';
import styles from './HelloWorld.module.scss';
import { IHelloWorldProps } from './IHelloWorldProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { useEffect, useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

export default class HelloWorld extends React.Component<IHelloWorldProps, {}> {

  public render(): React.ReactElement<IHelloWorldProps> {
    return (
      <div className={styles.helloWorld}>
        <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>
              <a href="https://aka.ms/spfx" className={styles.button}>
                <span className={styles.label}>Learn more</span>

                <Example></Example>
              </a>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

React Hooks Nedir?

0

React 16.8 sürümü ile React Hooks eklentisi tanıtıldı. React Hooks ile artık sınıf yazmamıza gerek kalmadan state tanımlaması ve React ‘ın diğer özelliklerini kullanmamıza olanak sağlamaktadır.

Neden React Hooks geliştirildi?

  • Component ‘ler arasında iletişimin sağlanması için props ya da High Order Component (HOC) kullanılmaktaydı, bu durumda da yazılımcı açısından component ‘lerin yeniden düzenlenmesi ya da kodun okunabilirliğini çok fazla düşürmekteydi. Ek olarak sürekli wrapper ile component ‘lerin iç içe olmasına sebep olmaktaydı.
  • React lifecycle içerisinde yer alan componentDidMount() ve componentDidUpdate() gibi method içerisinde hem listener ‘ların oluşturulması, silinmesi gibi işlemler yapılırken hem de API request ‘leri yapılmaktaydı. Bu durumda ilgili method ‘a bir çok fazla iş yükü yüklediğinden kodun kalitesini düşürmekte ve component içerisinde hatalara sebep olmaktaydı.
  • Custom olarak oluşturulan event ‘lerin “this” ile bind edilmesinin gerekliliği, bildiğiniz gibi butonun click event ‘ini aynı scope içerisinde kullanabilmemiz için constructor method ‘u içerisine “this.handleClick = this.handleClick.bind(this);” gibi işlemleri yapmaktaydık. Bu da aynı zamanda kod yığını olmakta ve minify işlemlerinde sorun olmasına sebep olmaktaydı.

Makalemize başlamadan önce bazı değinmek istediğim başlıkları belirteyim:

  • Opsiyoneldir yani mevcut projeniz içerisinde herhangi bir kodu tekrar yazmadan kullanabilirsiniz. Fakat 16.8 sürümünü kullanmanız durumunda Hooks kullanmayabilirsiniz.
  • Mevcut projeniz içerisindeki herhangi bir kodu değiştirmeniz gerekmemektedir. Yani sürümü yükseltmeniz durumunda Hooks kullanmayı zorunlu bırakmadığı ve this.setState gibi method lar depricated olmadığından dolayı yapınızda değişiklik yapmanız gerekmeyecektir.
  • Hooks, v16.8 sürümü ile birlikte kullanılmaktadır.

Şimdi React Hooks içerisindeki API ‘lere göz atalım.

Basic Hooks:

  • useState
  • useEffect
  • useContext

Additional Hooks:

  • useReducer
  • useCallback
  • useMemo
  • useRef
  • useImperativeHandle
  • useLayoutEffect
  • useDebugValue

useState

useState(), state hook olarak belirtilmektedir. Functional component içerisinde state işlemlerinizi gerçekleştirmenizi sağlamaktadır. Şimdi aşağıda kodu inceleyelim.

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

Yukarıdaki kod örneği tanıdık gelecektir. 🙂 Burada constructor içerisine “count” isimli state tanımlayıp, değerini “0” olarak set ‘liyoruz. Sonrasında ise buton ‘un click event ‘i ile “this.setState()” methodu ile değerini arttıyoruz.

Şimdi hooks ile örneğe göz atalım.

import React, { useState } from 'react';

function Example() {
  // "count" adında yeni bir state değişkeni tanımlayın.
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useState methodu iki tane değer return eder.

  • State tanımlanızı sağlar, yani “count” değişkenini tanımlar. this.state sınıfının sağladığı özellikleri kullanmanızı sağlar ve parametre olarak almış olduğu değeri, tanımladığınız değişkene set ‘ler. (Parametre olarak değer vermeyebilirsiniz.) Kısaca özetlemem gerekirse, “count” isimli değişken oluştur ve değerini “0” olarak tanımla diyoruz.
  • Diğer geri dönen değer ile tanımlamış olduğumuz state ‘in değerini değiştirmemizi sağlamaktadır. Yani this.setState method ‘unda gerçekleştirdiğimiz işlemi “setCount()” ile gerçekleştirmemize olanak tanımaktadır.

Tanımlamış olduğunuz değişkeni “this.state.count” yapmadan “count” olarak okuyabilirsiniz.

Çoklu state tanımlaması yapmak isterseniz aşağıdaki tanımlama yaparak işlemlerinizi gerçekleştirebilirsiniz.

function ExampleWithManyStates() {
  // Birden fazla state değişkeni bildir!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

useEffect

useEffect methodu, componentDidMount, componentDidUpdate, ve componentWillUnmount mehod ‘larının birleşimi olarak düşünebilirsiniz. DOM işlemlerini tamamladıktan sonra useEffect methodu çalışmaktadır. useEffect methodu component içerisinde oluşturduğumuz için state ve props değişkenlerine erişebilmektedir ve default olarak ilk render ‘da dahil olmak üzere her render işleminden sonra useEffect methodu çalıştırılır.

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Yukarıdaki örneğimizde DOM güncellenmesinden sonra document.title değiştirilmesi sağlanmaktadır.

Eskiden olsa nasıl yapıyor olacaktık:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }

  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

Şimdi biraz daha detaylı inceleyelim. Aşağıda hooks öncesine ait bir kod bloğu bulunmaktadır. Bu kod bloğunda kullanıcı çevrimiçi olduğunda abone oluyor ve sonrasında nasıl temizlendiği ile ilgili örnek mevcut.

class FriendStatus extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }

  render() {
    if (this.state.isOnline === null) {
      return 'Loading...';
    }
    return this.state.isOnline ? 'Online' : 'Offline';
  }
}

Yukarıdaki örnekte gördüğünüz gibi her iki method ‘u kullanmak yerine useEffect içerisine “cleanup” methodunu return ettiğimiz için temizlenmesini sağlamaktayız.

import React, { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

Aynı zamanda birden fazla useEffect methodu kullanabilirsiniz.

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  // ...
}

Yukarıda gördüğünüz gibi lifecycle içerisindeki karmaşadan kurtuluyoruz. 🙂

useContext

useContext ‘e geçiş yapmadan önce 16.3.0 ile kullanıma sunulan React Context API ‘ye değinelim. React uygulamanız içerisinde her yerden erişmek istediğiniz değerleriniz olabilir. Örneğin, tema seçimi gibi. Bu gibi işlemleri gerçekleştirebilmeniz için Context API kullanabilirsiniz. Şimdi giriş yapan bir kullanıcı için Context API kullanalım ve useContext ile farkına göz atalım.

UserContext isimli context oluşturalım ve UserContext.Provider ve UserContext.Consumer değerlerinden oluşacak.

  • Provider, UserContext içerine değer setlemizini sağlamaktadır.
  • Consumer, UserContext içerisindeki değerleri okumanıza olanak sağlamaktadır.
// src/UserContext.js
import React from 'react'

const UserContext = React.createContext({})

export const UserProvider = UserContext.Provider
export const UserConsumer = UserContext.Consumer
export default UserContext

Context ‘imizi oluşturduk.

//src/App.js
import React from 'react'
import HomePage from './HomePage'
import { UserProvider } from './UserContext'

function App() {
  const user = { name: 'Tania', loggedIn: true }

  return (
    <UserProvider value={user}>
      <HomePage />
    </UserProvider>
  )
}

UserProvider ile değerimizi set ‘ledik.

// src/HomePage.js (class example)
import React, { Component } from 'react'
import UserContext from './UserContext'

class HomePage extends Component {
  static contextType = UserContext

  componentDidMount() {
    const user = this.context

    console.log(user) // { name: 'Tania', loggedIn: true }
  }

  render() {
    return null
  }
}

Yukarıdaki örneğimizde HomePage component içerisinde context ‘e erişim log yazdırdık.

// src/HomePage.js (hooks example)
import React, { useContext } from 'react'
import UserContext from './UserContext'

function HomePage() {
  const user = useContext(UserContext)

  console.log(user) // { name: 'Tania', loggedIn: true }

  return null
}

Yukarıdaki örneğimiz ise useContext direkt olarak erişip, log yazdırabildik.

Kendi Hooks tasarlayın

React components arasında iletişimin sağlanması için props ya da HOC tarafından gerçekleştirildiğine değinmiştik. Bu da bazı sorunlara sebep olmaktaydı. Custom hooks ile bu durumun önüne geçmiş oluyoruz.

Önceki örneğimizde giriş yapan kullanıcının online olmasını ile ilgili geliştirme yapmıştık. Fakat bunu sadece o component içerisinde gerçekleştirdik. Diğer component ‘ler tarafından kullanmak istediğimizi varsayalım. Bu durum için önce abonelik ile ilgili işlemleri “useFriendStatus” methoduna alalım.

import React, { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

Yukarıdaki örneğimizde “friendID” parametresi ile status bilgisini return ediyoruz ve görmüş olduğunuz gibi useState ve useEffect gibi hooks kullanmaktayız. Bu kısımdaki parametre ve return edilecek değerler tamamen bizim ihtiyacımıza yönelik değişebilir. Yani kendi ihtiyacınıza göre parametre ve return değerlerinizi değiştirebilirsiniz.

React ‘ın custom hook olduğunu anlayabilmesi için function name “use” başlaması tavsiye edilmektedir.

Custom hook tanımladık. FriendStatus ve FriendListItem component olduğunu düüşünelim. Bu iki component içerisinde nasıl kullanacağımıza göz atalım.

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

Dikkat edilmesi gereken kurallar

  • Hooks, JavaScript fonksiyonları içerisinde kullanmayız. React functional component içerisinde kullanınız.
  • Component ‘lerin top-level kısmında çağırınız. İç içe geçmiş fonksiyonlarınızda hooks kullanmayınız.

Yukarıdaki iki kuralı projenizde kullanmak isterseniz, eslint-plugin-react-hooks ESLint plugin mevcut. Yüklemek için aşağıdaki kod bloğunu çalıştırınız.

npm install eslint-plugin-react-hooks --save-dev
// Your ESLint configuration
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks
    "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies
  }
}