Реакция useContext не вызывает повторную визуализацию - PullRequest
0 голосов
/ 10 июля 2020

Итак, я пытаюсь использовать настраиваемый обработчик, который использует useContext, который, как я ожидал, вызовет повторную визуализацию моего компонента ToastContainer при изменении ToastContext. Однако компонент ToastContainer не выполняет повторную отрисовку при изменении контекста. При использовании инструментов разработчика я вижу, что контекст действительно изменен обработчиком, но новые данные не отображаются.

Извините за весь код, я просто не уверен, в чем заключается ошибка

useToast. js

function useToast () {
  let [toasts, setToasts] = useContext(ToastContext)
  

  function createToast(message, color, duration = 0) {
    let id = Math.floor(Math.random() * 1000)
    toasts.set(id, <Toast {...{ message, color, duration, id }} />)
    setToasts(toasts)

    if (duration) {
      setTimeout(() => { toasts.delete(id); setToasts(toasts)}, duration * 1000)
    }
  }

  return [toasts, createToast]
}

ToastContainer. js

function ToastContainer (props) {
  let [toasts, setToasts] = useContext(ToastContext)
  return( <> {[...toasts.values()]} </>)
}

стр. js

function Page (props) {  
    let [toasts, createToast] = useToast()  
    createToast("hello", 'red')
    createToast("world", 'yellow')

    return(<Article />)
}

приложение js

function App({Component, pageProps}) {


  const toastState = useState(new Map())

  return (
    <>
          <ToastContext.Provider value={toastState}>
            <ToastContainer/>
            <main>
                <Component {...pageProps}></Component>
            </main>
          </ToastContext.Provider>
    </>
  )

1 Ответ

0 голосов
/ 10 июля 2020

Итак, пара вещей:

Вызывая toasts.set(id, <Toast {...{ message, color, duration, id }} />), вы напрямую изменяете свое состояние, чего вы не хотите делать. Затем вы вызываете setToasts с тем же самым объектом Map, чтобы он не запускал повторную визуализацию, поскольку это та же ссылка.

Кроме того, если это сработало, путем вызова createToast() в ваш функциональный компонент во время его рендеринга вызвал бы исключение Maximum update depth exceeded, как и:

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

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

Вы можете использовать Map, но вам нужно будет сделать что-то вроде:

const [myMap, setMyMap] = useState(new Map());
const updateMap = (k,v) => {
  setMyMap(new Map(myMap.set(k,v)));
}

как показано на https://medium.com/swlh/using-es6-map-with-react-state-hooks-800b91eedd5f. Это создаст новый объект Map с парами ключ-значение текущего Map.

В качестве альтернативы вы можете использовать объект {} с парой настроек:

const toastState = useState({});

setToasts({
  ...toasts,
  [id]: <Toast key={id} {...{ message, color, duration, id }} />
});

function ToastContainer (props) {
  let [toasts, setToasts] = useContext(ToastContext)
  return Object.values(toasts);
}

if (duration) {
  setTimeout(() => {
    const newToasts = { ...toasts };
    delete newToasts[id];
  }, duration * 1000)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...