Не могу понять, как создать «базовое» специальное приложение для приложения react / NextJS

#reactjs #next.js

Вопрос:

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

У меня есть крючок (с использованием SWR), который возвращает мне сеанс пользователя, и внутри крючка он возвращает логическое значение для issuebscribed. Я намерен использовать это.

 const session = useSession();

if(session.isLoading) {
   return <></>;
}

if(!session.isSubscribed) {
   /* redirect the user*/
} 

return (
  <p>HTML of the page / component</p>
)
 

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

В качестве дополнительного преимущества было бы полезно добавить сеанс в качестве опоры в «новый компонент», чтобы мне не приходилось дважды вызывать крючок.

Спасибо за все и любую помощь.

p.s. я упоминаю об этом в названии, но я использую NextJS. Не уверен, что в этом есть какая-то оголенность (я не думаю, что это так, но стоит упомянуть)

Комментарии:

1. Вы читали документы? reactjs.org/docs/higher-order-components.html , есть несколько примеров, которые вы можете использовать, также я бы написал «пример компонента высокого порядка» в Google и посмотрел, как его пишут другие люди, иногда это копипаст, но хорошо знать основы

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

3. вы работаете над функциональными или классовыми компонентами ?

4. функционально, я думаю, именно поэтому я не смог разобраться с документацией (которую я только что перечитал и все еще в замешательстве).

5. В функциональных лучше использовать пользовательские крючки — они более читабельны и просты в создании, вы можете проверить их здесь — reactjs.org/docs/hooks-custom.html . Это выглядит очень сложно, но поверьте мне, это действительно легко понять, просто проверьте документы и посмотрите одно видео на YouTube или что-то в этом роде

Ответ №1:

Вы можете создать оболочку, например, следующим образом;

 const withSession = (Component: NextComponentType<NextPageContext, any, {}>) => {
  const Session = (props: any) => {
    const session = useSession();

    if (session.isLoading) {
      return <>Loading..</>
    }
    else {
      return <Component {...props} />
    }
  };

  // Copy getInitial props so it will run as well
  if (Component.getInitialProps) {
    Session.getInitialProps = Component.getInitialProps;
  }

  return Session;
};
 

И чтобы использовать его на своей странице или компоненте, вы можете просто сделать как;

 const UserDetailPage: React.FC = (props) => {
  // ...
  // component's body
  return (<> HI </>);
};

export default withSession(UserDetailPage);
 

Комментарии:

1. Это именно то, что мне было нужно, хотя типы вызывают ошибку в VSCode Argument of type '(props: PageProps) => JSX.Element' is not assignable to parameter of type 'NextComponentType<NextPageContext, any, {}>'.

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

Ответ №2:

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

Мы могли бы реализовать Session компонент, который будет использовать useSession крючок и условно отображать компоненты, передаваемые через children опору:

 const Session = props => {
    const { isLoading } = useSession();
    if (isLoading) {
        return "Loading...";
    }

    return props.children;
};
 

Затем вложите Page компонент в Session :

 const GuardedPage: React.FC<PageProps> = props => {
    return (
        <Session>
            <Page {...props} />
        </Session>
    );
};
 

Я вижу, что на этот вопрос уже дан ответ, просто хотел предложить альтернативу. Одним из преимуществ такого подхода является то , что мы можем обернуть произвольное дерево в Session , а не только в Page .

Комментарии:

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

2. Это, вероятно, вопрос терминологии, но я понимаю, что компонент более высокого порядка должен либо принимать компонент, либо возвращать компонент (или то и другое). Это именно то, что withSession следует из принятого ответа, что делает его специальным. Но здесь Session компонент берет элемент с помощью children реквизита и возвращает элемент , поэтому, с моей точки зрения, это просто обычный компонент react.

Ответ №3:

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

Давайте определим (СПЕЦИАЛЬНЫЙ) компонент более высокого порядка для вашей проблемы. С помощью HOC логика может быть модулирована и перераспределена между компонентами. Это означает, что ваше создание должно иметь возможность вызывать различные методы в одном источнике данных или один метод, который будет применяться к нескольким компонентам. Например, предположим, что у вас есть компонент API с 5 конечными точками (вход, подписка, выход из системы, отмена подписки). HOC должен иметь возможность использовать любую из конечных точек из любого другого компонента, в котором вы его используете. HOC используется для создания абстракции, которая позволит вам определить логику в одном месте.

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

 const session = useSession();

if(session.isLoading) {
   return <></>;
}

if(!session.isSubscribed) {
   /* redirect the user*/
} 

return (
  <p>HTML of the page / component</p>
) 
 

Первое, что я вижу неправильным в приведенном выше коде, — это вариант использования специального компонента, у которого нет инструкции по экспорту, которой можно поделиться с другими компонентами. Кроме того, зачем использовать 2 оператора возврата для isLoading, если не требуется проверять оба условия (isLoading amp; isSubscribed) Кроме того, зависят ли эти условные операторы друг от друга или от отдельных функций, которые можно вызывать отдельно из другого источника? если бы вы опубликовали больше своего кода или компонентов, в которые вы его вставляете, это помогло бы?

Использовать это в качестве специального в NEXT, по сути, то же самое, что и в react. Зависимая логика

 const session = useSession(props);
// ad constructor and state logic 
... 

if(session.isLoading) {
   return this.setState({isLoading: true});
} else { 
  return this.setState({isSubscribed: false});
}
 

Отдельная логика

 const session = useSession(props);
// ad constructor and state logic 
... 

isLoading () => { 
  return this.setState({isLoading: true});
} 


isSubscribed() => { 
  return this.setState({isSubscribed: true});
} 
 

или что — то в этом роде, использующее маршруты…

 import React, { Component } from 'react';
import { Redirect, Route } from 'react-router-dom';

export const HOC = { 

  isState: false, 

  isSubscribed(props) {
    this.isState = false;
    setTimeout(props, 100);
  },
  isLoading(props) {
    this.isState = true;
    setTimeout(props, 100);
  }
};

export const AuthRoute = ({ component: Component, ...rest}) => { 

  return (
  <Route {...rest} render={(props) => (
     HOC.isAuthenticated === true ? <Component {...props} /> : <Redirect to='/' /> 
  )}/>
)};


}
 

Если бы вы могли поделиться большим количеством своего кода, это было бы более полезно? или один из компонентов, которые вам нужно скопировать и вставить из исходного специального кода. Мне было бы проще, чем колоть в темноте, чтобы помочь в вашей проблеме, но я надеюсь, что это поможет!

Ваше здоровье!