Реагировать на глобальное состояние без каких-либо недостатков контекста или сокращения? - PullRequest
0 голосов
/ 01 августа 2020

Недавно я изучил следующую статью: Управление состоянием с помощью React Hooks - без Redux или Context API . С самого начала реакции наиболее обсуждаемым вопросом всегда является управление состоянием и глобальное состояние. Redux был популярным выбором, а в последнее время - контекстным API. Но этот подход кажется намного проще, меньше кода и более масштабируем.

Мой вопрос: может ли кто-нибудь увидеть обратную сторону использования такого подхода к управлению состоянием, который я, возможно, упустил из виду. Я немного изменил код для поддержки SSR, и он работает в Next js, а также сделал его немного более удобным для использования действий и настройки переменной состояния.

Вот код:

Codesandbox Demo

useGlobalState. js

import React, { useState, useEffect, useLayoutEffect } from 'react';

const effect = typeof window === 'undefined' ? useEffect : useLayoutEffect;

function setState(newState) {
    if (newState === this.state) return;
    this.state = newState;
    this.listeners.forEach((listener) => {
        listener(this.state);
    });
}

function useCustom() {
    const newListener = useState()[1];
    effect(() => {
        this.listeners.push(newListener);
        return () => {
            this.listeners = this.listeners.filter((listener) => listener !== newListener);
        };
    }, []);
    return [this.state, this.setState, this.actions];
}

function associateActions(store, actions) {
    const associatedActions = {};
    if (actions) {
        Object.keys(actions).forEach((key) => {
            if (typeof actions[key] === 'function') {
                associatedActions[key] = actions[key].bind(null, store);
            }
            if (typeof actions[key] === 'object') {
                associatedActions[key] = associateActions(store, actions[key]);
            }
        });
    }
    return associatedActions;
}

const useGlobalHook = (initialState, actions) => {
    const store = { state: initialState, listeners: [] };
    store.setState = setState.bind(store);
    store.actions = associateActions(store, actions);
    return useCustom.bind(store, React);
};

export default useGlobalHook;

Затем настроить пользовательский обработчик для переменной состояния может быть простой строкой или объектом вот простой:

import useGlobalState from './useGlobalState';

const initialState = 'Hi';

// Example action for complex processes setState will be passed to component for use as well
const someAction = (store, val) => store.setState(val); 

const useValue = useGlobalState(initialState, { someAction });

export default useValue;

И использовать в компоненте:

import React from 'react'
import useVal from './useVal'

export default () => {
  const [val, setVal, actions] = useVal();

  const handleClick = () => {
    setVal('New Val');
    // or use some actions
    actions.someAction('New Val');
  }

  return(
    <div>{val}</div>
    <button onClick={handleClick}>Click Me</button>
  )
}

Все это кажется намного более чистым и простым подходом, и мне интересно, почему это не go подойти для государственного управления в React. Во-первых, вам не нужно все оборачивать в провайдере. Далее, это очень легко реализовать, и в фактическом приложении задействуется гораздо меньше кода. Может ли кто-нибудь увидеть обратную сторону такого подхода. Единственное, о чем я могу думать, это проблема повторного рендеринга, которая есть у context api, но небольшими частями это не должно быть проблемой.

1 Ответ

0 голосов
/ 02 августа 2020

хороший подход, но я все еще считаю, что redux лучше для более крупных приложений, особенно когда дело касается производительности. Пример, использующий ваш подход, добавляет кнопку как отдельный компонент, оборачивая его с помощью React.memo и запуская actions.toggle() из компонента кнопки, но кнопка повторно визуализируется 2 раза, что не влияет на измененное состояние.

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

...