useFooController/useFooHook을 통해 useContext를 사용하는 구성 요소의 렌더 제한
구성요소에 사용자 정의 후크를 사용하고 있으며 사용자 정의 후크는 사용자 정의 컨텍스트를 사용한다.고려하다
/* assume FooContext has { state: FooState, dispatch: () => any } */
const useFoo = () => {
const { state, dispatch } = useContext(FooContextContext)
return {apiCallable : () => apiCall(state) }
}
const Foo = () => {
const { apiCallable } = useFoo()
return (
<Button onClick={apiCallable}/>
)
}
많은 구성 요소가 변경될 예정임FooState
다른 구성요소(양식 입력 등)로부터.내가 보기엔 마치Foo
사용하다useFoo
, , 를 사용한다.state
로부터FooStateContext
. 이것은 에 대한 모든 변화를 의미하는가?FooContext
를 Foo
안 그래? 때 경우는 안 돼그것은 누군가가 버튼을 클릭할 때에만 상태를 활용하면 되지만, 그렇지 않으면 절대로 사용하지 않는다.낭비가 심한 것 같다.
나는 생각하고 있었다.useCallback
특별히 이걸 위한거야 그래서 난 생각중이야return {apiCallable : useCallback(() => apiCall(state)) }
하지만 그 다음엔 덧붙이자면[state]
의 두 번째 매개 변수로서useCallback
그럼 주(州)가 업데이트될 때마다 콜백은 다시 리뉴얼된다는 뜻이니, 나도 같은 문제로 돌아왔지?
이런 맞춤 훅은 처음 해보는 거야..useCallback
어떻게 하면 내가 원하는 것을 이룰 수 있을까?
편집 다른 방법으로, 나는 이 상태의 중첩된 속성에 작은 변경사항을 발송할 많은 구성요소를 가지고 있지만, 이 특정 구성요소는 RESTful API를 통해 전체 상태 객체를 전송해야 하지만 그렇지 않으면 상태를 사용하지 않는다.이 구성 요소를 완전히 렌더링하는 것은 상관이 없다.입력 키프레스(예: 키프레스)를 통해 상태를 지속적으로 변경할 때에도 이 구성요소가 렌더링되지 않도록 하고 싶다.
네가 질문에서 Typecript 유형을 제공했으므로, 나는 그것들을 나의 답변에 사용할 것이다.
첫 번째 방법: 컨텍스트 분할
다음 유형의 컨텍스트 지정:
type ItemContext = {
items: Item[];
addItem: (item: Item) => void;
removeItem: (index: number) => void;
}
컨텍스트를 다음과 같은 유형의 두 개의 개별 컨텍스트로 분할할 수 있다.
type ItemContext = Item[];
type ItemActionContext = {
addItem: (item: Item) => void;
removeItem: (index: number) => void;
}
그러면 제공되는 구성요소는 다음 두 컨텍스트 사이의 상호작용을 처리할 것이다.
const ItemContextProvider = () => {
const [items, setItems] = useState([]);
const actions = useMemo(() => {
return {
addItem: (item: Item) => {
setItems(currentItems => [...currentItems, item]);
},
removeItem: (index: number) => {
setItems(currentItems => currentItems.filter((item, i) => index === i));
}
};
}, [setItems]);
return (
<ItemActionContext.Provider value={actions}>
<ItemContext.Provider value={items}>
{children}
</ItemContext.Provider>
</ItemActionContext.Provider>
)
};
이렇게 하면 하나의 더 큰 결합된 컨텍스트의 일부인 두 개의 다른 컨텍스트에 액세스할 수 있을 것이다.
기본 ItemContext는 항목이 추가 및 제거될 때 업데이트되어 해당 항목을 소비하는 모든 항목에 대한 렌더링을 발생시킨다.
표시된 ItemActionContext는 업데이트되지 않으며(setState 기능은 평생 동안 변경되지 않음) 소비 구성요소에 대한 렌더링을 직접 유발하지 않는다.
두 번째 방법: 일부 버전의 서브스크립션 기반 가치
만약 당신이 컨텍스트의 가치를 절대 변하지 않게 만든다면(대체 대신 Mutate, HAS THE WORLD GOUND CRAZY?!) 당신은 당신이 필요로 하는 데이터를 보관하고 리렌더를 최소화하는 간단한 객체를 설정할 수 있다. 마치 가난한 맨스 리벤덱스(아마 이제 Redex를 사용할 때인가?) 같은 것이다.
다음과 유사한 클래스를 만들 경우:
type Subscription<T> = (val: T) => void;
type Unsubscribe = () => void;
class SubscribableValue<T> {
private subscriptions: Subscription<T>[] = [];
private value: T;
constructor(val: T) {
this.value = val;
this.get = this.get.bind(this);
this.set = this.set.bind(this);
this.subscribe = this.subscribe.bind(this);
}
public get(): T {
return this._val;
}
public set(val: T) {
if (this.value !== val) {
this.value = val;
this.subscriptions.forEach(s => {
s(val)
});
}
}
public subscribe(subscription: Subscription<T>): Unsubscriber {
this.subscriptions.push(subscription);
return () => {
this.subscriptions = this.subscriptions.filter(s => s !== subscription);
};
}
}
다음과 같은 유형의 컨텍스트가 생성될 수 있다.
type ItemContext = SubscribableValue<Item[]>;
제공되는 구성 요소는 다음과 유사하다.
const ItemContextProvider = () => {
const subscribableValue = useMemo(() => new SubscribableValue<Item[]>([]), []);
return (
<ItemContext.Provider value={subscribableValue}>
{children}
</ItemContext.Provider>
)
};
그런 다음 필요에 따라 사용자 지정 후크를 사용하여 값을 액세스할 수 있다.
// Get access to actions to add or remove an item.
const useItemContextActions = () => {
const subscribableValue = useContext(ItemContext);
const addItem = (item: Item) => subscribableValue.set([...subscribableValue.get(), item]);
const removeItem = (index: number) => subscribableValue.set(subscribableValue.get().filter((item, i) => i === index));
return {
addItem,
removeItem
}
}
type Selector = (items: Item[]) => any;
// get access to data stored in the subscribable value.
// can provide a selector which will check if the value has change each "set"
// action before updating the state.
const useItemContextValue = (selector: Selector) => {
const subscribableValue = useContext(ItemContext);
const selectorRef = useRef(selector ?? (items: Item[]) => items)
const [value, setValue] = useState(selectorRef.current(subscribableValue.get()));
const useEffect(() => {
const unsubscribe = subscribableValue.subscribe(items => {
const newValue = selectorRef.current(items);
if (newValue !== value) {
setValue(newValue);
}
})
return () => {
unsubscribe();
};
}, [value, selectorRef, setValue]);
return value;
}
이렇게 하면 선택기 기능을 사용하여 리렌더를 줄일 수 있다(reactive Redex's의 극히 기본적인 버전과 같음).useSelector
구독 가능한 값(root object)은 해당 기간 동안 참조를 변경하지 않으므로.
이것의 단점은 구독을 관리하고 항상 사용한다는 것이다.set
가입이 통지되도록 보류 값을 업데이트하는 기능.
결론:
아마 다른 사람들이 이 문제를 공격할 수 있는 많은 다른 방법들이 있을 것이고 당신은 당신의 문제에 맞는 것을 찾아야 할 것이다.
컨텍스트/상태 요구사항이 더 큰 범위를 가질 경우 이 문제를 해결하는 데 도움이 될 수 있는 타사 라이브러리(Redex 등)가 있다.
이것은 FooContext에 대한 모든 변경 사항이 Foo 구성요소를 다시 렌더링한다는 것을 의미하는가?
현재 (v17
)), 컨텍스트 API에 대한 구제금융은 없다.내 다른 답에 예를 들어보자.그렇다, 그것은 항상 상황 변화에 따라 바뀔 것이다.
그것은 누군가가 버튼을 클릭할 때에만 상태를 활용하면 되지만, 그렇지 않으면 절대로 사용하지 않는다.낭비가 심한 것 같다.
컨텍스트 공급자를 분할하여 수정할 수 있으므로 위의 동일한 답변을 참조하십시오.
'programing' 카테고리의 다른 글
Vue js 자식 구성 요소에서 정의되지 않은 소품.하지만 그 대본에서만 (0) | 2022.04.07 |
---|---|
Vue 구성 요소의 Vuex 돌연변이에 대한 호출을 테스트하는 방법 (0) | 2022.04.07 |
중복 인덱스로 판다 줄 제거 (0) | 2022.04.06 |
외부 JS 스크립트를 VueJS 구성 요소에 추가하는 방법 (0) | 2022.04.06 |
해시/앵커가 있는 페이지에 대한 nuxt 링크 탐색 문제 (0) | 2022.04.06 |