Как сделать изменение state при переходе между страницами с помощью стрелок
Суть, нужно сделать чтобы state нормально изменялся при переходе между страницами с помощью стрелок. Например: ты заполнил строку эмайл и перешёл на след этап ввода пароля и там если нажать стрелку назад (вернуться на страницу ввода эмайла) stage продолжит иметь статус password .
useView.ts
import { useForm, UseFormReturn } from 'react-hook-form'
import { emailFormScheme, EmailFormScheme } from '../constants/emailFormScheme'
import { useEffect, useState } from 'react'
import { passwordFormScheme, PasswordFormScheme } from '../constants/passwordFormScheme'
import { zodResolver } from '@hookform/resolvers/zod';
import { useNavigate } from 'react-router-dom';
import { AboutFormScheme, aboutFormScheme } from '../constants/aboutFormScheme';
export type stages = 'email' | 'password' | 'about'
export const useView = () => {
const navigate = useNavigate()
const [stage, setStage] = useState<stages>('email')
const signUpForm = useForm<EmailFormScheme | PasswordFormScheme | AboutFormScheme>({
mode: 'onBlur',
defaultValues: {
email: '',
password: '',
username: '',
birthDate: '',
},
resolver: zodResolver(stage === 'email' ? emailFormScheme : stage === 'password' ? passwordFormScheme : stage === 'about' ? aboutFormScheme : emailFormScheme)
})
const onSubmit = signUpForm.handleSubmit(value => {
if (stage === 'email' && 'email' in value) {
navigate('passwordStage')
setStage('password')
return
}
if (stage === 'password' && 'password' in value) {
navigate('aboutStage')
setStage('about')
return
}
})
const back = () => {
switch(stage) {
case 'password': {
setStage('email')
navigate(-1)
break
}
case 'about' : {
setStage('password')
navigate(-1)
break
}
}
}
return {
form: signUpForm,
stage,
functions: { onSubmit, back }
}
}
import React from 'react'
import { Box, IconButton, Typography, useTheme } from '@mui/material'
import Header from './components/header/header'
import { useView } from './hooks/useView'
import { Outlet } from 'react-router-dom'
import { ProgressBar } from './components/progressBar/progressBar'
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
import styles from './signUp.module.scss'
export type ContextType = ReturnType<typeof useView>;
export const SignUp = () => {
const theme = useTheme()
const { form, stage, functions } = useView()
return (
<Box
width='100vw'
height='100vh'
display='flex'
flexDirection='column'
alignItems='center'
sx={{ background: theme.palette.background.default }}
>
<Header />
<Box
width='324px'
mt={5}
>
<Outlet context={{ form, functions, stage } satisfies ContextType} />
</Box>
</Box>
)
}
import { SignUp, PasswordStage, EmailStage, AboutStage, StageViewer } from '@spotify/signUp'
import { createBrowserRouter } from 'react-router-dom'
import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';
export const router = createBrowserRouter([
{
path: '/signUp',
element: <SignUp />,
children: [
{
index: true,
element: <EmailStage/>
},
{
path: '',
element: <StageViewer/>,
children: [
{
path: 'passwordStage',
element: <PasswordStage/>
},
{
path: 'aboutStage',
element: <AboutStage/>
}
]
}
]
}
])
Ответы (1 шт):
браузерные стрелки не обновляют страницу(только дублируют действие каторое было совершено до), следовательно проблема не в стрелках, вот наглядный пример где state остается после переходов между страницами. Единственное что меняется это mount/unmount страницы, логично что после этого все состояние в страницах будет переинициализировано заного, если что то надо сахранить, то это должно быть вне страниц в каторых происходит mount/unmount.
если же вот прям все обновляется, наверное можно в LocalStorage либо в url дабавить данные на время
и если в целом надо сахранить stage на катором пользователь, если даже у него комп сдохнет, то это делается отправкой данных на бекенд с последуюшим получением в тот момент когда пользователь вернется обратно к форме.
import { NavLink, Outlet, createBrowserRouter } from 'react-router-dom';
import {
createContext,
Dispatch,
FC,
ReactNode,
SetStateAction,
useContext,
useMemo,
useState,
} from 'react';
type TS = {
state: number;
setState: Dispatch<SetStateAction<number>>;
};
const Context = createContext<TS>({} as TS);
const CountProvider = ({ children }: { children: ReactNode }) => {
const [state, setState] = useState(0);
const value = useMemo(() => ({ state, setState }), [state]);
return <Context.Provider value={value}>{children}</Context.Provider>;
};
const useCountContext = () => useContext(Context);
const App = () => {
return (
<div>
<NavLink to={`/contacts1`}>contacts 1</NavLink>
<NavLink to={`/contacts2`}>contacts 2</NavLink>
<CountProvider>
<Outlet />
</CountProvider>
</div>
);
};
const Contacts1: FC = () => {
const { setState, state } = useCountContext();
return (
<div>
<span>number : {state}</span>
<button
onClick={() => {
setState((prev) => ++prev);
}}
>
incr
</button>
</div>
);
};
const Contacts2: FC = () => {
const { setState, state } = useCountContext();
return (
<div>
<span>number : {state}</span>
<button
onClick={() => {
setState((prev) => ++prev);
}}
>
incr
</button>
</div>
);
};
export const router = createBrowserRouter([
{
path: '/',
element: <App />,
children: [
{
path: '/contacts1',
element: <Contacts1 />,
},
{
path: '/contacts2',
element: <Contacts2 />,
},
],
},
]);