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.
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.
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
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
}
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.
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.
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.
Okuduğunuz içi teşekkür ederim. 🙂
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.
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.
Bu durum hem sayfanın yavaşlamasına hem de tekrar eden kod bloklarına sebep olmaktadır.
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.
md corporate-library
cd corporate-library
yo @microsoft/sharepoint
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.
npm link
Bu sayede lokalimizde diğer projelerimizde kullanmak üzere npm link ile hazırlamış olduk.
npm link example-library
import * as ExampleLibrary from 'example-library';
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.
gulp bundle --ship
gulp package-solution --ship
"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"
},
gulp bundle --ship
gulp package-solution --ship
Library component hayatımızı çok kolaylaştırmaktadır fakat bazı dikkat edilmesi gereken husus bulunmaktadır:
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. 🙂
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.
npm kullanıyorsanız:
npm i -g @pnp/office365-cli
yarn kullanıyorsanız:
yarn global add @pnp/office365-cli
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/sp-core-library@1.9.1
```
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/sp-lodash-subset@1.9.1
```
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/sp-office-ui-fabric-core@1.9.1
```
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/sp-webpart-base@1.9.1
```
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/sp-property-pane@1.9.1
```
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/sp-build-web@1.9.1
```
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/sp-module-interfaces@1.9.1
```
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/sp-webpart-workbench@1.9.1
```
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/sp-tslint-rules@1.9.1
```
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/rush-stack-compiler-2.9@0.7.16
```
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/sp-core-library@1.9.1 @microsoft/sp-lodash-subset@1.9.1 @microsoft/sp-office-ui-fabric-core@1.9.1 @microsoft/sp-webpart-base@1.9.1 @microsoft/sp-property-pane@1.9.1
npm i -DE @microsoft/sp-build-web@1.9.1 @microsoft/sp-module-interfaces@1.9.1 @microsoft/sp-webpart-workbench@1.9.1 @microsoft/sp-tslint-rules@1.9.1 @microsoft/rush-stack-compiler-2.9@0.7.16
```
### 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"
}
```
o365 spfx project upgrade --output md > report.md
Okuduğunuz için teşekkür ederim. 🙂
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 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.
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 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?
Makalemize başlamadan önce bazı değinmek istediğim başlıkları belirteyim:
Şimdi React Hooks içerisindeki API ‘lere göz atalım.
Basic Hooks:
Additional Hooks:
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.
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 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 ‘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.
// 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.
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>
);
}
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
}
}