Предоставьте значение формы formik поставщику контекста

У меня есть компонент/форма <Login>, которая использует <Formik> для отслеживания состояния моих форм. Есть конкретное значение props.values.userType, которое я хочу передать поставщику контекста, чтобы я мог передать это свойство моему компоненту маршрутизации.

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

Поэтому я создал AuthContext.

const AuthContext = React.createContext();

В моем компоненте <Login> у меня есть компонент <Formik> ниже. Где я должен использовать AuthContext.Provider и как передать values.props.userType этому провайдеру? Должен ли props.values.userType быть инициализирован в состоянии компонента класса, в котором живет этот <Formik> компонент?

Или я должен создать хранилище объектов в состоянии, которое отслеживает userType? Что-то вроде этого

export const AuthContext = createContext({
  user: null,
  isAuthenticated: null
});

У меня кодыпесочница здесь.

class FormikLoginForm extends Component {
  constructor(props) {
  super(props);

this.state = {};
}

render() {
const {} = this.state;

return (

<Formik
      initialValues = {{
        username: "",
        password: "",
        userType: "",
      }}
      onSubmit = {(values, { setSubmitting }) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          setSubmitting(false);
        }, 500);
      }}
      validationSchema = {Yup.object().shape({
        userType: Yup.string().required("User type is required"),
        username: Yup.string().required(
          "Required -- select a user type role"
        ),
        password: Yup.string().required("Password is required"),
      })}
    >
      {props => {
        const {
          values,
          touched,
          errors,
          dirty,
          isSubmitting,
          handleChangeEvent,
          handleBlur,
          handleSubmit,
          handleReset
        } = props;
        return (
          <>
            <Grid>
              <Grid.Column>
                <Header as = "h2" color = "teal" textAlign = "center">
                  Log-in to your account
                </Header>
                <Form size = "large" onSubmit = {handleSubmit}>
                  <Segment stacked>
                    <RadioButtonGroup
                      id = "userType"
                      label = "User Type"
                      value = {values.userType}
                      error = {errors.userType}
                      touched = {touched.userType}
                    >

Затем в моем файле index.js, где я визуализирую все свои маршруты, у меня есть мой AdminRoute, который использует логику, описанную выше.

const AdminRoute = props => {
  const { userType, ...routeProps } = props;
  if (userType !== "admin") return <Redirect to = "/login" />;
  return <Route {...routeProps} />;
};

const Routes = () => (
  <Router>
    <Switch>
      <Route exact path = "/" component = {Home} />
      <Route path = "/login" component = {FormikLoginForm} />
      <Route exact path = "/admin" component = {AdminPage} />
      />
      <Route path = "/admin/change-password" component = {ChangePassword} />
    </Switch>
  </Router>
);
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
0
4 235
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Поскольку вы используете React Router, я бы рекомендовал следовать примеру в их документах для поток аутентификации и создать компонент PrivateRoute и использовать его вместо обычного компонента Route.

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

Что касается userType, мне кажется, что это то, что вы должны получить в качестве заявления об успешном входе в систему через конечную точку API или из любого используемого вами бэкэнда входа. И да, вы можете сохранить это в своем AuthContext и использовать его так (при условии, что вы используете React 16.8+ в настройке вашего проекта):

function AdminPrivateRoute({ component: Component, ...rest }) {
  const auth = React.useContext(AuthContext);
  return (
    <Route
      {...rest}
      render = {props =>
        auth.isAuthenticated && auth.userType === 'admin' ? (
          <Component {...props} />
        ) : (
          <Redirect
            to = {{
              pathname: "/login",
              state: { from: props.location }
            }}
          />
        )
      }
    />
  );
}

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

// may want to pass initial auth state as a prop
function AuthProvider({ children }) {
  const [state, setState] = React.useState({
    isAuthenticated: false,
    userType: null,
    // other data related to auth/user
  });

  // may or may not have use for React.useMemo here
  const value = {
    ...state,
    // login() does not validate user credentials
    // it simply sets isAuthenticated and userType
    login: (user) => setState({ isAuthenticated: true, userType: user.type }),
    // logout() only clears isAuthenticated, will also need to clear auth cookies
    logout: () => setState({ isAuthenticated: false, userType: null }),
  };

  return (
    <AuthContext.Provider value = {value}>{children}</AuthContext.Provider>
  );
}

Не могли бы вы предоставить рабочий пример, разветвив коды и ящик, которые я предоставил?

DJ2 16.07.2019 16:03

В вашем образце есть некоторые ошибки, но временная работа над ними будет выглядеть так: codeandbox.io/s/logincomponent-rq44y

Simon Ingeson 16.07.2019 16:23

Потрясающий. Это проясняет мое замешательство. И последний вопрос: если я хочу изменить способ отображения входа/выхода в строке меню, что мне нужно передать этому компоненту меню? Например, если администратор аутентифицирован и вошел в систему, отображать только кнопку «Выход»?

DJ2 16.07.2019 17:37

Так же, как и для пользовательского компонента маршрута, вы должны использовать AuthContext для проверки подлинности пользователя. Базовый образец здесь: codeandbox.io/s/logincomponent-le4cm

Simon Ingeson 17.07.2019 18:05

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

DJ2 17.07.2019 22:18

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