Как избежать setState в хуке useEffect, вызывающем второй рендер - PullRequest
0 голосов
/ 01 июня 2019

Я пишу пользовательский хук, который принимает идентификатор в качестве входных данных и затем должен выполнить следующие задачи:

  • получить данные для этого идентификатора синхронно из магазина
  • подписаться наизменения в этом хранилище и обновите данные соответственно

Я придумал следующую реализацию, у которой есть недостаток - я устанавливаю состояние непосредственно из ловушки эффекта, вызывая второй рендеринг.

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 и не полагаясь накакое-то неиспользованное фиктивное состояние?

1 Ответ

0 голосов
/ 01 июня 2019

Итак, теперь вы используете useState внутри своего хука только для повторного запуска рендеринга хост-компонента после изменения хранилища.Как насчет того, чтобы взять обработчик изменений извне?

function useData(id, onChanged) {
  useEffect(() => {
    return store.onChange(id, onChanged);
  }, [id, onChanged]);

 return store.getData(id);
}
...