[ 살펴보기 ] Recoil - Atom Effects
![[ 살펴보기 ] Recoil - Atom Effects](https://cdn.hashnode.com/res/hashnode/image/upload/v1715784295413/152126d3-a236-4892-91a0-2d3c37363f60.jpeg)
Atom effects는 atom에 변경이 발생했을 때를 catch하여 변경에 다른 side effect를 발생시킬 수 있다 ( React useEffect와 유사하다 )
기본적인 형태는 다음과 같다
export const userListState = atom<UserAtom[]>({
key: "userListState",
default: userListDefaultState,
effects: [
() => {
console.log(" ::: userListState effect :::");
},
],
});
만약 effects array에 여러개의 effect function을 전달하면 전달한 순서대로 실행된다
export const userListState = atom<UserAtom[]>({
key: "userListState",
default: userListDefaultState,
effects: [
() => {
console.log(" ::: userListState effect :::");
},
() => {
console.log(" ::: userListState effect 2 :::");
},
],
});
setSelf
effect function의 setSelf를 통해 현재 atom의 값을 업데이트 할 수 있다. 아래와 같이 설정하면 effect가 실행될 때 atom의 value가 { name:"jack", age:23 }으로 업데이트 된다
export const userListState = atom<UserAtom[]>({
key: "userListState",
default: [],
effects: [
({ setSelf }) => {
setSelf([{ name: "jack", age: 23 }]);
},
],
});
OnSet
onSet을 통해 atom에 변경이 발생했을 때 마다 side effect를 처리한다. onSet에서 아래의 예제와 같이 업데이트 된 새로운 value, 업데이트 되기 전 value, 그리고 atom의 변경사항이 reset 함수를 통해 발생한 것이지 체크할 수 있다
export const userListState = atom<UserAtom[]>({
key: "userListState",
default: [{ name: "jack", age: 23 }],
effects: [
({ onSet }) => {
onSet((newVal, oldValue, isReset) => {
console.log({ newVal, oldValue, isReset });
});
},
],
});
다만 setSelf를 통해 update가 발생하면 onSet는 실행되지 않는다
export const userListState = atom<UserAtom[]>({
key: "userListState",
default: [{ name: "", age: 0 }],
effects: [
({ onSet, setSelf }) => {
setSelf([{ name: "jake2", age: 20 }]);
/*
위의 setSelf로 인해 atom이 업데이트 되어도
아래 onSet은 실행되지 않는다
*/
onSet((newVal, oldValue, isReset) => {
console.log({ newVal, oldValue, isReset });
});
},
],
});
LocalStorage와 연결하여 사용하기
다음과 같이 atom effects를 통해 브라우저의 localStorage의 특정 값과 atom을 연결하여 사용할 수 있다
export const userListState = atom<UserAtom[]>({
key: "userListState",
default: [{ name: "", age: 0 }],
effects: [
({ onSet, setSelf, trigger }) => {
const savedValue = localStorage.getItem("myInfo");
if (savedValue != null) {
setSelf(JSON.parse(savedValue));
}
onSet((newValue, oldValue, isReset) => {
isReset
? localStorage.removeItem("myInfo")
: localStorage.setItem("myInfo", JSON.stringify(newValue));
});
},
],
});
위의 예제를 살펴보면 effect가 처음 발생할 때 localStorage에서 값을 가져와 값이 있다면 현재 atom에 업데이트 한다
그리고 그 이후에 atom의 값에 변경이 있다면 onSet에서 변경사항을 catch해 localStorage에 저장하거나 reset이 발생한다면 해당 localStorage 값을 초기화 한다
비동기 처리와 Suspense
Atom effects에서 비동기 처리를 통해 data를 업데이트 해야 한다면 다음과 같이 처리할 수 있을 것이다.
첫 번째 방법은 setSelf에 Promise객체 자체를 전달하는 것 것이다.
export const userListState = atom<UserAtom[]>({
key: "userListState",
default: [{ name: "", age: 0 }],
effects: [
({ onSet, setSelf, trigger }) => {
const getAsyncData = async () => {
const result = await apiGetTestData();
return result.data;
};
setSelf(getAsyncData());
onSet((newValue, oldValue, isReset) => {
console.log({ newValue, oldValue, isReset });
});
},
],
});
만약 위의 atom을 사용하는 component 상단에 Suspense로 처리가 되어 있다면 sefSelf에 전달된 promise가 resolve되게 전까지는 Suspense의 fallback으로 대체된다 ( NextJS와 사용할 때 dev 환경 또는 build시 pending 상태에서 resolve되지 않는 현상이 보이는 것 같아 주의가 필요 )
반면 다음과 같이 비동기 처리를 마치고 최종 값만 setSelf에 전달한다면 Suspense는 사용되지 않고 우선 detault에 설정된 값이 우선 사용되며 비동기 처리가 모두 끝나고 난 뒤에 atom 값이 업데이트 된다
export const userListState = atom<UserAtom[]>({
key: "userListState",
default: [{ name: "", age: 0 }],
effects: [
({ onSet, setSelf, trigger }) => {
const getAsyncData = async () => {
const result = await apiGetTestData();
setSelf(result.data);
};
getAsyncData();
onSet((newValue, oldValue, isReset) => {
console.log({ newValue, oldValue, isReset });
});
},
],
});
![[ 살펴보기 ] RDB - Relationships](https://cdn.hashnode.com/res/hashnode/image/upload/v1739711556668/48dc9e84-a621-42aa-9c9f-5fc5c436f0ec.jpeg)
![[ 살펴보기 ] MySQL - Data types](https://cdn.hashnode.com/res/hashnode/image/upload/v1739593589113/530f8704-4d27-42c9-a451-bb5c63150b99.jpeg)
![[ 살펴보기 ] TypeORM - Transactions, Migration](https://cdn.hashnode.com/res/hashnode/image/upload/v1739106042581/980b8133-61d4-406a-a026-65be9c28eace.jpeg)
![[ 살펴보기 ] TypeORM - Relations](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666874402/b688bd0b-b6bb-4f43-87d8-c1b46b59f1b7.jpeg)
![[ 살펴보기 ] TypeORM - Basics](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666803591/bef5df17-7dc7-4123-ae55-004d5042df39.jpeg)