Я пишу пользовательский хук, который принимает идентификатор в качестве входных данных и затем должен выполнить следующие задачи:
- получить данные для этого идентификатора синхронно из магазина
- подписаться наизменения в этом хранилище и обновите данные соответственно
Я придумал следующую реализацию, у которой есть недостаток - я устанавливаю состояние непосредственно из ловушки эффекта, вызывая второй рендеринг.
function useData({id}) {
// set initial data on first render
const [data, setData] = useState(Store.getData(id));
useEffect(() => {
// when id changes, set data to whatever is in store at the moment
// here we call setData directly from inside useEffect, causing a second render
setData(Store.getData(id));
// subscribe to changes to update data whenever it changes in the store
return Store.onChange(id, setData);
}, [id]);
return data;
}
Второй подход, который я попробовал, заключался в добавлении фиктивного состояния, которое существует только для повторной визуализации.При таком подходе я напрямую возвращаю данные, полученные из Store.getData ().Это гарантирует, что я получу самые свежие данные при каждом рендеринге, а useEffect гарантирует, что каждый триггер onChange вызовет новый рендеринг.
function useData({id}) {
// adding some dummy state that we only use to force a render
const [, setDummy] = useState({});
const refresh = useCallback(() => {
setDummy({});
}, []);
useEffect(() => {
// subscribe to changes cause a refresh on every change
return Store.onChange(id, refresh);
}, [id, refresh]);
return Store.getData[id];
}
Второй подход работает хорошо, но кажется странным добавлять это фиктивное состояние.Конечно, я мог бы поместить это в другую ловушку useRefresh, но я не уверен, будет ли это действительно хорошей практикой.
Есть ли лучший способ реализовать это, не вызывая setData напрямую из useEffect и не полагаясь накакое-то неиспользованное фиктивное состояние?