React Context fornisce un metodo alternativo per gestire lo stato dell'applicazione.
Normalmente lo stato di una applicazione viene mantenuto nel componente di root e fatto passare, tramite le proprietà, agli altri componenti con la tecnica detta Prop Drilling. React Prop Drillingcon React Context API è possibile spostare lo stato al di fuori dell'applicazione ed accedervi direttamente da ogni singolo componenteReact ContextQuesto approccio risulta molto utile nel caso di componenti molto annidati.
Il contesto va definito con l'istruzione React.createContext
React JSX: UserContext
import * as React from 'react';
// come esempio gestisco lo stato dell'utente
export interface IUser {
loginName: string;
modified: Date;
}
// il contesto comprenderà la proprietà ed il metodo per modificare IUser
interface IUserContext {
user: IUser;
setUser: (loginName: IUser) => void
}
// creo il contesto
const UserContext = React.createContext<IUserContext | null>(null);
export default UserContext;
Definire un provider
Successivamente va completato con la definizione di un provider
React JSX: UserProvider
import * as React from 'react';
import { FC, ReactElement, useState } from 'react';
export interface IUser {
loginName: string;
modified: Date;
}
interface IUserContext {
user: IUser;
setUser: (loginName: IUser) => void
}
// definisco il tipo di proprietà che verranno passate al Provider
type UserProviderProps = {
user: IUser, // valore di default del contesto
children: JSX.Element // gli elementi figli del provider
};
const UserContext = React.createContext<IUserContext | null>(null);
// creo una funzione (FC) che rappresenta il Provider
export const UserProvider: FC<UserProviderProps> = (props): ReactElement => {
// uso useState per memorizzare lo stato del contesto
const [user, setUser] = useState<IUser>({
loginName: props.user.loginName,
modified: new Date
});
return (
// definisco il Provider del context passando lo stato da memorizzare
<UserContext.Provider value={{ user, setUser }}>{props.children}</UserContext.Provider>
)
}
export default UserContext;
Consumare il contesto
Per poter consumare il contesto, prima di tutto, devo fare il wrap del componente di root con il provider UserProvider
React JSX: Root UserProvider
import * as React from 'react';
import styles from './HelloWordContext.module.scss';
import { IHelloWordContextProps } from './IHelloWordContextProps';
import { UserProvider } from '../contexts/UserContext';
export default class HelloWordContext extends React.Component<IHelloWordContextProps, {}> {
public render(): React.ReactElement<IHelloWordContextProps> {
return (
<UserProvider user={{loginName: 'utente1', modified: new Date()}}>
<sectio className={`${styles.helloWordContext} ${hasTeamsContext ? styles.teams : ''}`}>
<ShowUser />
<hr />
<ButtonUser />
</section>
</UserProvider>
);
}
}
A questo punto posso creare un componente ShowUser che consuma i dati del contesto
React JSX: ShowUser
import * as React from 'react';
import { FC, ReactElement } from 'react';
import UserContext from '../contexts/UserContext';
const ShowUser: FC = (): ReactElement => {
// recupero il contesto
const { user } = React.useContext(UserContext);
const modified = new Intl.DateTimeFormat('it-IT', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
}).format(user?.modified)
return (
<span>LoginName: {user?.loginName}, modified: {modified}</span>
)
};
export default ShowUser;
Notare l'uso di Intl.DateTimeFormat(...) per formattare le date in italiano senza l'uso di librerie esterne.
Oltre a visualizzare i dati del contesto, posso anche modificarlo
React JSX: ButtonUser
import * as React from 'react';
import { FC, ReactElement } from 'react';
import UserContext from '../contexts/UserContext';
const ButtonUser: FC = (): ReactElement => {
// recupero il contesto e quello che mi serve
const { user, setUser } = React.useContext(UserContext);
// creo un handler che al click modifica la data modified
const handlerClick = (): void => setUser({ loginName: user.loginName, modified: new Date() });
return (
<button type='button' onClick={handlerClick}>Set date</button>
)
};
export default ButtonUser;