как использовать useMediaQuery в компоненте класса - PullRequest
4 голосов
/ 10 января 2020

При использовании функций в качестве компонентов у вас есть возможность использовать хук useMediaQuery из material-ui. Однако это нигде не показывает, как использовать этот хук внутри класса.

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

import React from 'react';
import useMediaQuery from '@material-ui/core/useMediaQuery';

const withMediaQuery = (...args) => Component => props => {
  const mediaQuery = useMediaQuery(...args);
  return <Component mediaQuery={mediaQuery} {...props} />;
};

export default withMediaQuery;

Однако при добавлении его в класс следующим образом:

export default withStyles(styles)(withMediaQuery(Main));

Это дает мне такую ​​ошибку:

index.js:1 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.

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

render() {

    const { classes, children } = this.props;

    const isDesktop = useMediaQuery(theme => theme.breakpoints.up('lg'), {
      defaultMatches: true,
    });

    const shouldOpenSidebar = isDesktop ? true : this.state.openSidebar;

    return (
      <div
        className={cc({
          [classes.root]: true,
          [classes.shiftContent]: isDesktop,
        })}>
        <Topbar
          onSidebarOpen={this.handleSidebarOpen}
        />
        <Sidebar
          onClose={this.handleSidebarClose}
          open={shouldOpenSidebar}
          variant={isDesktop ? 'persistent' : 'temporary'}
        />
        <main className={classes.content}>
          {children}
        </main>
      </div>
    );
  }

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

Ответы [ 2 ]

1 голос
/ 10 января 2020

Вы не предоставляете args, необходимый для useMediaQuery, поэтому Main передается как args, и функция, ожидающая возврата компонента. Когда React пытается выполнить рендеринг (вызвать функцию), возвращаемое значение является другой функцией, которая не является значением дочернего элемента реагирования.

Вызовите функцию - withMediaQuery и передайте ей медиазапросы, а затем передайте Main возвращаемой функции.

Пример:

export default withStyles(styles)(withMediaQuery('(min-width:600px)')(Main));
0 голосов
/ 02 мая 2020

Вместо того, чтобы ограничивать себя только одним медиа-запросом, лучше сMediaQuery HO C может быть

import React from 'react'
import useMediaQuery from '@material-ui/core/useMediaQuery'

export const withMediaQuery = (queries = []) => Component => props => {
  const mediaProps = {}
  queries.forEach(q => {
    mediaProps[q[0]] = useMediaQuery(q[1])
  })
  return <Component {...mediaProps} {...props} />
}

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

export default withStyles(styles)(withMediaQuery([
    ['isDesktop', theme => theme.breakpoints.up('lg'), {
      defaultMatches: true
    }]
  ]))

В вашем компоненте вы можете запросить имена проп напрямую в render

render() {

    const { classes, children, IsDesktop = false } = this.props;

    const shouldOpenSidebar = IsDesktop ? true : this.state.openSidebar;

    return (
      <div
        className={cc({
          [classes.root]: true,
          [classes.shiftContent]: isDesktop,
        })}>
        <Topbar
          onSidebarOpen={this.handleSidebarOpen}
        />
        <Sidebar
          onClose={this.handleSidebarClose}
          open={shouldOpenSidebar}
          variant={isDesktop ? 'persistent' : 'temporary'}
        />
        <main className={classes.content}>
          {children}
        </main>
      </div>
    );
  }
...