Как показать/скрыть счетчики, закусочные или другие временные компоненты с помощью React Function Components

Лучше ли отображать спиннеры, закусочные и т. д. в отдельных элементах DOM, а не добавлять их в основное дерево компонентов приложения? В компонентах класса React было очень легко получить ссылку на методы компонентов класса, чтобы показать/скрыть счетчик. С новыми функциональными компонентами React Hooks это уже не так просто. Если я помещу счетчик в основное дерево компонентов, смогу ли я использовать новый хук «useContext», чтобы показать/скрыть счетчик?

Ниже показан глобальный счетчик React Hooks, использующий Material-UI, который работает, но очень хакерский. Как сделать это более изящным?

namespace Spinner {
   'use strict';

   export let show: any; // Show method ref.
   export let hide: any; // Hide method ref.

   export function Render() {
      const [visible, setVisible] = React.useState(false); //Set refresh method.

      function showIt() {
         setVisible(true); // Show spinner.
      }

      function hideIt() {
         setVisible(false); // Hide spinner.
      }

      const styles: any = createStyles({
         col1Container: { display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column' },
      });

      return (
         <div>
            {visible && <div style = {styles.col1Container}>
               <CircularProgress key = {Util.uid()}
                  color='secondary'
                  size = {30}
                  thickness = {3.6}
               />
            </div>}

            <SetSpinnerRefs showRef = {showIt} hideRef = {hideIt} />
         </div>
      ); // end return.
   } // end function.

   const mounted: boolean = true;

   interface iProps {
      showRef();
      hideRef();
   }

   function SetSpinnerRefs(props: iProps) {
      // ComponentDidMount.
      React.useEffect(() => {
         Spinner.show = props.showRef;
         Spinner.hide = props.hideRef;
      }, [mounted]);

      return (<span />);
   }
} // end module.
В компонентах класса React было очень легко получить ссылку на методы компонентов класса, чтобы показать/скрыть счетчик. — если вы имеете в виду конкретную ситуацию, рассмотрите возможность публикации кода для «простых» и «сложных» компонентов. Могу ли я использовать новый хук «useContext», чтобы показать/скрыть счетчик? — возможно, вы могли бы, а возможно, и не могли. Это зависит.
Estus Flask 07.03.2019 22:59

@estus - проблема в том, что я не понимаю, как использовать хук «useContext», поэтому я, вероятно, буду делать что-то хакерское, например, вызывать ReactDOM.render для глобального компонента счетчика каждый раз, когда я хочу его показать/скрыть.

Lambert 08.03.2019 14:53

Публикация «неправильного» stackoverflow.com/help/mcve помогла бы решить проблему более актуальным образом. useContext заменяет контекст Consumer. Если вы знаете, как сделать то, что вы описываете, пожалуйста, напишите пример. Если вы знаете, как это сделать с помощью render, вам тоже поможет пример. На данный момент вопрос слишком широк.

Estus Flask 08.03.2019 15:15

@estus - я добавил пример кода в этот пост, как вы и предложили. Есть ли способ сделать его более элегантным и менее хакерским?

Lambert 15.03.2019 20:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
4
2 716
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

In React class components, it was really easy to get a reference to the class components methods to show/hide the spinner

Вы можете продолжать использовать компоненты класса. Они никуда не денутся ?

Не очень хороший способ

На мой взгляд, на самом деле плохая практика - использовать методы класса для отображения и скрытия счетчика. Предполагая, что ваш API выглядит как

<Spinner {ref=>this.something=ref}/>

И вы используете

this.something.show(); // or .hide

Лучший способ

<Spinner shown = {state.shown}/>

Теперь вы можете изменить state.shown вместо сохранения ссылки и использования show / hide.

Мне нравится, чтобы все было просто, и у меня есть только один глобальный компонент счетчика, который я могу показать/скрыть. Я полагаю, что в приведенном выше примере мне потребуется добавить хук состояния «показанный» к каждому компоненту в приложении, где я хочу показать/скрыть счетчик. Это правильно?

Lambert 08.03.2019 14:43

Я добавил пример кода в этот пост. Есть ли способ сделать его более элегантным и менее хакерским?

Lambert 15.03.2019 16:46

Проблема аналогична Вот этот, и решение для счетчиков будет таким же, как и для модальных окон. Хуки React не меняют его работы, но могут сделать его более лаконичным.

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

const SpinnerContext = React.createContext();

const SpinnerContainer = props => {
  const [visible, setVisible] = React.useState(false);

  const spinner = useMemo(() => ({
    show: () => setVisible(true),
    hide: () => setVisible(false),
  }), []);

  render() {
    return <>
      {visible && <Spinner />}
      <SpinnerContext.Provider value = {spinner}>
        {props.children}
      </SpinnerContext.Provider>
    </>;
  }
}

Который передается с контекстом:

const ComponentThatUsesSpinner = props => {
  const spinner = useContext(SpinnerContext);
  ...
  spinner.hide();
  ...
}

<SpinnerContainer>
  ...
  <ComponentThatUsesSpinner />
  ...
</SpinnerContainer>

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

   <Spinner.Render />  {/* Build spinner component */}
   Spinner.show();     //Show spinner.

namespace Spinner {
   'use strict';
   export let show: any; //Ref to showIt method.
   export let hide: any; //Ref to hideIt method.

   export function Render() {
      const [visible, setVisible] = React.useState(false); //Set refresh method.

      function showIt() {
         setVisible(true);  //Show spinner.
      }
      function hideIt() {
         setVisible(false); //Hide spinner.
      }

      const showRef: any = React.useRef(showIt);
      const hideRef: any = React.useRef(hideIt);

      //Component did mount.
      React.useEffect(() => {
         Spinner.show = showRef.current;
         Spinner.hide = hideRef.current;
      }, []);

      const styles: any = createStyles({
         row1Container: { display: 'flex', alignItems: 'center', justifyContent: 'center' },
      });

      return (
         <div>
            {visible && <div style = {styles.row1Container}>
               <CircularProgress
                  color='secondary'
                  size = {30}
                  thickness = {3.6}
               />
            </div>}
         </div>
      ); //end return.

   } //end function.
} //end module.

Другие вопросы по теме