Refactor/scope and context (#1960)

* wip

* Test with Dropdown

* wip

* wip

* Finished removing DropdownRecoilScopeContext

* Fix from PR
This commit is contained in:
Lucas Bordeau
2023-10-11 15:35:47 +02:00
committed by GitHub
parent a342af74d1
commit 22451a68b3
61 changed files with 531 additions and 426 deletions

View File

@ -5,6 +5,10 @@ import { RecoilScopeContext as RecoilScopeContextType } from '@/types/RecoilScop
import { RecoilScopeContext } from '../states/RecoilScopeContext';
/**
*
* @deprecated Use a custom scope context instead, see example with DropdownScope
*/
export const RecoilScope = ({
children,
scopeId,

View File

@ -1,5 +1,9 @@
import { Context, useContext } from 'react';
/**
* @deprecated use a custom scope instead and desctructure the scope id from the scope context
* Get the scope context with useScopeInternalContext
*/
export const useContextScopeId = (SpecificContext: Context<string | null>) => {
const recoilScopeId = useContext(SpecificContext);

View File

@ -2,6 +2,9 @@ import { useContext } from 'react';
import { RecoilScopeContext } from '@/types/RecoilScopeContext';
/**
* @deprecated Use a custom scope instead and desctructure the scope id from the scope context
*/
export const useRecoilScopeId = (RecoilScopeContext: RecoilScopeContext) => {
const recoilScopeId = useContext(RecoilScopeContext);

View File

@ -1,25 +1,21 @@
import { Context, useContext } from 'react';
import { RecoilState, useRecoilState } from 'recoil';
import { RecoilState, SerializableParam, useRecoilState } from 'recoil';
import { RecoilScopeContext } from '../states/RecoilScopeContext';
import { ScopedFamilyStateKey } from '../scopes-internal/types/ScopedFamilyStateKey';
export const useRecoilScopedFamilyState = <StateType>(
recoilState: (familyUniqueId: string) => RecoilState<StateType>,
uniqueIdInRecoilScope: string,
CustomRecoilScopeContext?: Context<string | null>,
export const useRecoilScopedFamilyState = <
StateType,
FamilyKey extends SerializableParam,
>(
recoilState: (
scopedFamilyKey: ScopedFamilyStateKey<FamilyKey>,
) => RecoilState<StateType>,
scopeId: string,
familyKey: FamilyKey,
) => {
const recoilScopeId = useContext(
CustomRecoilScopeContext ?? RecoilScopeContext,
return useRecoilState<StateType>(
recoilState({
scopeId,
familyKey,
}),
);
if (!recoilScopeId)
throw new Error(
`Using a scoped atom without a RecoilScope : ${
recoilState('').key
}, verify that you are using a RecoilScope with a specific context if you intended to do so.`,
);
const familyUniqueId = recoilScopeId + uniqueIdInRecoilScope;
return useRecoilState<StateType>(recoilState(familyUniqueId));
};

View File

@ -0,0 +1,14 @@
import { RecoilState, useRecoilState } from 'recoil';
import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey';
export const useRecoilScopedStateV2 = <StateType>(
recoilState: (scopedKey: ScopedStateKey) => RecoilState<StateType>,
scopeId: string,
) => {
return useRecoilState<StateType>(
recoilState({
scopeId,
}),
);
};

View File

@ -3,6 +3,9 @@ import { RecoilState, RecoilValueReadOnly, useRecoilValue } from 'recoil';
import { RecoilScopeContext } from '../states/RecoilScopeContext';
/**
* @deprecated use useRecoilScopedStateV2 instead
*/
export const useRecoilScopedValue = <T>(
recoilState: (param: string) => RecoilState<T> | RecoilValueReadOnly<T>,
CustomRecoilScopeContext?: Context<string | null>,

View File

@ -0,0 +1,14 @@
import { RecoilState, useRecoilValue } from 'recoil';
import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey';
export const useRecoilScopedValueV2 = <StateType>(
recoilState: (scopedKey: ScopedStateKey) => RecoilState<StateType>,
scopeId: string,
) => {
return useRecoilValue<StateType>(
recoilState({
scopeId,
}),
);
};

View File

@ -0,0 +1,20 @@
import { ScopeInternalContext } from '../types/ScopeInternalContext';
import { useScopeInternalContext } from './useScopeInternalContext';
export const useAvailableScopeIdOrThrow = <T extends { scopeId: string }>(
Context: ScopeInternalContext<T>,
scopeIdFromProps?: string,
): string => {
const scopeInternalContext = useScopeInternalContext(Context);
const scopeIdFromContext = scopeInternalContext?.scopeId;
if (scopeIdFromProps) {
return scopeIdFromProps;
} else if (scopeIdFromContext) {
return scopeIdFromContext;
} else {
throw new Error('Scope id is not provided and cannot be found in context.');
}
};

View File

@ -0,0 +1,11 @@
import { useContext } from 'react';
import { ScopeInternalContext } from '../types/ScopeInternalContext';
export const useScopeInternalContext = <T extends { scopeId: string }>(
Context: ScopeInternalContext<T>,
) => {
const context = useContext(Context);
return context;
};

View File

@ -0,0 +1,19 @@
import { useContext } from 'react';
import { isDefined } from '~/utils/isDefined';
import { ScopeInternalContext } from '../types/ScopeInternalContext';
export const useScopeInternalContextOrThrow = <T extends { scopeId: string }>(
Context: ScopeInternalContext<T>,
) => {
const context = useContext(Context);
if (!isDefined(context)) {
throw new Error(
`Using a scope context without a ScopeInternalContext.Provider wrapper for context : ${Context.displayName}.`,
);
}
return context;
};

View File

@ -0,0 +1,4 @@
import { Context } from 'react';
export type ScopeInternalContext<T extends { scopeId: string }> =
Context<T | null>;

View File

@ -0,0 +1,6 @@
import { SerializableParam } from 'recoil';
export type ScopedFamilyStateKey<FamilyKey extends SerializableParam> = {
scopeId: string;
familyKey: FamilyKey;
};

View File

@ -0,0 +1,3 @@
export type ScopedStateKey = {
scopeId: string;
};

View File

@ -0,0 +1,13 @@
import { Context, createContext } from 'react';
import { ScopedStateKey } from '../types/ScopedStateKey';
type ScopeInternalContext<T extends ScopedStateKey> = Context<T | null>;
export const createScopeInternalContext = <T extends ScopedStateKey>(
initialValue?: T,
) => {
return createContext<T | null>(
initialValue ?? null,
) as ScopeInternalContext<T>;
};

View File

@ -0,0 +1,19 @@
import { atomFamily, SerializableParam } from 'recoil';
import { ScopedFamilyStateKey } from '../scopes-internal/types/ScopedFamilyStateKey';
export const createScopedFamilyState = <
ValueType,
FamilyKey extends SerializableParam,
>({
key,
defaultValue,
}: {
key: string;
defaultValue: ValueType;
}) => {
return atomFamily<ValueType, ScopedFamilyStateKey<FamilyKey>>({
key,
default: defaultValue,
});
};

View File

@ -0,0 +1,14 @@
import { atomFamily } from 'recoil';
export const createScopedState = <ValueType>({
key,
defaultValue,
}: {
key: string;
defaultValue: ValueType;
}) => {
return atomFamily<ValueType, { scopeId: string }>({
key,
default: defaultValue,
});
};