React Context API + withRouter - можем ли мы использовать их вместе? - PullRequest
0 голосов
/ 30 декабря 2018

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

Я отслеживаю состояние modalOpen, используя контекстный API.

Итак, пользователь нажимает кнопку на панели навигации.Модал Открывается.Модал имеет контейнер с именем QuoteCalculator.

QuoteCalculator выглядит следующим образом:

class QuoteCalculator extends React.Component {
    static contextType = ModalContext;
    // ...

    onSubmit = () => {
        // ...
        this.context.toggleModal();
        this.props.history.push('/quote');
        // ..
    };

    render() {
       //...
       return(<Question {...props} next={this.onSubmit} />;)
    }
}

export default withRouter(QuoteCalculator);

Теперь все работает как положено.Когда пользователь отправляет, я иду по правильному маршруту.Я просто вижу следующее предупреждение на консоли

index.js: 1446 Предупреждение: withRouter (QuoteCalculator): Компоненты функций не поддерживают contextType.

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

Я попытался использовать Redirect в качестве альтернативы.Что-то вроде

QuoteCalculator looks as follows:

    class QuoteCalculator extends React.Component {
        static contextType = ModalContext;
        // ...

        onSubmit = () => {
            // ...
            this.context.toggleModal();
            this.setState({done: true});
            // ..
        };

        render() {
           let toDisplay;
           if(this.state.done) {
               toDisplay = <Redirect to="/quote"/>
            } else {
               toDipslay = <Question {...props} next={this.onSubmit} />;
            }
           return(<>{toDisplay}</>)
        }
    }

    export default QuoteCalculator;

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

Вы пытались перенаправить на тот же маршрут, на котором вы сейчас находитесь

Кроме того, я бы предпочел не использовать этот подход, просто потому, что тогда мне пришлось бы отменить состояние «сделано» (в противном случае, когда пользователь снова нажимает кнопку «Готово», значение «истина», и мы просто будем перенаправлены)...

Есть идеи, что происходит сRouter и history.push?

Вот мое приложение

class App extends Component {
    render() {
        return (
            <Layout>
                <Switch>
                    <Route path="/quote" component={Quote} />
                    <Route path="/pricing" component={Pricing} />
                    <Route path="/about" component={About} />
                    <Route path="/faq" component={FAQ} />
                    <Route path="/" exact component={Home} />
                    <Redirect to="/" />
                </Switch>
            </Layout>
        );
    }
}

1 Ответ

0 голосов
/ 31 декабря 2018

Источник предупреждения

В отличие от большинства компонентов более высокого порядка, withRouter заключает в себе передаваемый компонент внутри функционального компонента вместо компонента класса.Но он все еще вызывает hoistStatics, который принимает статический contextType и перемещает его в компонент функции, возвращаемый withRouter.Обычно это должно быть хорошо, но вы нашли случай, когда это не так.Вы можете проверить репо код для более подробной информации, но оно короткое, поэтому я просто опущу соответствующие строки для вас:

function withRouter(Component) {
  // this is a functional component
  const C = props => {
    const { wrappedComponentRef, ...remainingProps } = props;

    return (
      <Route
        children={routeComponentProps => (
          <Component
            {...remainingProps}
            {...routeComponentProps}
            ref={wrappedComponentRef}
          />
        )}
      />
    );
  };

  // ...
  // hoistStatics moves statics from Component to C
  return hoistStatics(C, Component);
}

Это действительно не должно негативно повлиятьчто-нибудь.Ваш контекст будет по-прежнему работать и будет просто игнорироваться в компоненте переноса, возвращенном из withRouter.Тем не менее, это не сложно изменить вещи, чтобы устранить эту проблему.

Возможные решения

Простейшее

Поскольку все, что вам нужно в вашем модале, это history.push, вы можете просто передать это как реквизит из родительского компонента модала.Учитывая настройки, которые вы описали, я предполагаю, что модал включен в одно место в приложении, довольно высоко в дереве компонентов.Если компонент, включающий ваш модал, уже является компонентом Route, он имеет доступ к history и может просто передать push модалу.Если это не так, то оберните родительский компонент в withRouter, чтобы получить доступ к реквизитам маршрутизатора.

Неплохо

Вы также можете сделать свой модальный компонент простымобертка вокруг вашего модального содержимого / функциональности, используя компонент ModalContext.Consumer для передачи необходимого контекста в качестве реквизита вместо использования contextType.

const Modal = () => (
  <ModalContext.Consumer>
    {value => <ModalContent {...value} />}
  </ModalContext.Consumer>
)

class ModalContent extends React.Component {
  onSubmit = () => {
    // ...
    this.props.toggleModal()
    this.props.history.push('/quote')
   // ..
  }

  // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...