Как вызвать обновление состояния контекста реагирования / или вызвать методы из нереагирующих классов? - PullRequest
0 голосов
/ 03 ноября 2019

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

Я хочу изменить это состояние и обновить пользовательский интерфейс из обычного метода полностью вне компонентов React. т.е. НЕ функциональный компонент или класс, просто обычный фрагмент кода JS.

Из того, что я вижу, провайдер / контекст могут быть доступны только из метода рендеринга или React.FC

Я могу передать функцию в , но она кажется только из некоторого типа компонента React, который расположен между <Context.Provider>

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

Есть ли способ, которым я могу создать некоторый тип store, который я могу просто вызвать setState() метод для своих данных, но где такие обновления будут реагировать в пользовательском интерфейсе?

[править] Причина, по которой я этого хочу, заключается в том, что у меня есть внешний вызов API, который дает мне длительный обратный вызов. Я не вижу необходимости оборачивать этот API во все виды реагирующих вещей, так как я хочу, чтобы этот модуль был переносимым (например, на стороне сервера) и просто взаимодействовал с состоянием приложения для обновления отображения пользовательского интерфейса.

Ответы [ 2 ]

1 голос
/ 03 ноября 2019

Насколько я могу судить, вам все еще нужно выбрать React API, если вы хотите создать пользовательский интерфейс с React.

Вот что вам нужно сделать:

  • Нужноконтекст для совместного использования значения в дереве компонентов
  • Требуется компонент поставщика в корне
  • Требуется подписка на внешний API для получения новых значений и установки этого значения в вашем контексте
  • Использование получателя контекста для получения общего значения

Вот пример как это может работать

0 голосов
/ 03 ноября 2019

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

Один вариант;как вы уже упоминали;это создать свой собственный магазин и магазин провайдера. Может быть, что-то вроде этого будет работать для вас:

const store = (initialState => {
  let value = initialState;
  let listeners = [];
  const getState = () => value;
  const setState = fn => {
    value = fn(value);
    listeners.forEach(l => l(value));
  };
  const subscribe = listener => {
    listeners.push(listener);
    return () =>
      (listeners = listeners.filter(f => f !== listener));
  };
  return { getState, setState, subscribe };
})({ counter: 1 }); //pass initial state to IIFE

const Store = React.createContext();

function Provider({ store, children }) {
  const [state, setState] = React.useState(
    store.getState()
  );
  React.useEffect(
    () =>
      store.subscribe(() => {
        const lastState = store.getState();
        //if a lot of setState calls are made synchronously
        //  do not update dom but let it batch update state
        //  before triggering a render
        Promise.resolve().then(() => {
          if (lastState === store.getState()) {
            setState(store.getState());
          }
        });
      }),
    [store]
  );
  return (
    <Store.Provider value={state}>
      {children}
    </Store.Provider>
  );
}

function App() {
  const state = React.useContext(Store);
  return <div>{state.counter}</div>;
}

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

//call store setState from anywhere
setInterval(
  () =>
    store.setState(state => ({
      ...state,
      counter: state.counter + 1,
    })),
  1000
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
...