#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='/' />
)}/>
)};
}
Если бы вы могли поделиться большим количеством своего кода, это было бы более полезно? или один из компонентов, которые вам нужно скопировать и вставить из исходного специального кода. Мне было бы проще, чем колоть в темноте, чтобы помочь в вашей проблеме, но я надеюсь, что это поможет!
Ваше здоровье!