React hooks: шаблоны активируемых состояний - PullRequest
3 голосов
/ 21 марта 2019

Я пытаюсь создать компонент, который может активировать / отключать некоторые функции в зависимости от реквизита. Для всех этих функций требуется состояние, которым нужно управлять.

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

WAY # 1

function useFunctionality(initState, enable) {
    if (!enable) {
        return null;
    }

    const [funct, updateFunct] = useState(init);
    return funct;
}

function Component({ enableFunct }) {
    const funct = useFunctionality('test', enableFunct);
    return (...);
}

WAY # 2

function useFunctionality(initState, enable) {
    const [funct, updateFunct] = useState(init);
    return enable ? funct : null;
}

function Component({ enableFunct }) {
    const funct = useFunctionality('test', enableFunct);
    return (...);
}

В обоих случаях крючки продолжают работать. Вопрос в том, каким образом вы чувствуете себя более правильным? Есть лучший способ сделать это?

Ответы [ 2 ]

2 голосов
/ 21 марта 2019

У обоих рецептов есть проблемы.

Способ 1 потенциально позволяет условно вызывать ловушку при рендеринге компонента, это может привести к ошибке и не рекомендуется :

Не вызывать Хуки внутри циклов, условий или вложенных функций. Вместо этого всегда используйте Hooks на верхнем уровне вашей функции React. Следуя этому правилу, вы гарантируете, что хуки вызываются в одном и том же порядке каждый раз при рендеринге компонента. Это то, что позволяет React правильно сохранять состояние хуков между несколькими вызовами useState и useEffect.

Как объяснено в в этом ответе , это правило можно отменить, если гарантируется, что условие не изменяется между визуализациями.

Чтобы гарантировать это, запомните условие:

function useFunctionality(initState, enable) {
    const condition = useMemo(() => enable, []);

    if (!condition)
        return null;

    const [funct, updateFunct] = useState(initState);
    return funct;
}

Способ 2 предпочтительнее, потому что он чище, а useState звонок не дорогой.

Оба способа имеют одну и ту же проблему, они используют состояние, которое никогда не меняется. Если это намерение, это вариант использования для ссылки. Поскольку оно никогда не изменяется, условие может быть помещено в качестве начального значения:

function useFunctionality(initState, enable) {
    return useRef(enable ? initState: null).current;
}
0 голосов
/ 21 марта 2019

Если вы хотите отключить использование определенной функциональности на основе реквизита, лучшим способом является не выполнять функциональность вместо выполнения всей логики и возврата нулевого или неопределенного, потому что нам не нужен ответ. Таким образом, первый подход лучше

function useFunctionality(initState, enable) {
    if (!enable) {
        return null;
    }

    const [funct, updateFunct] = useState(init);
    return funct;
}

function Component({ enableFunct }) {
    const funct = useFunctionality('test', enableFunct);
    return (...);
}

Это может быть особенно важно, когда вычисления внутри пользовательских хуков стоят дорого.

...