Estou enfrentando um problema ao configurar o middleware de rotas privadas no React. Ao acessar uma rota privada, invoco o componente “RequireAuth” que valida se o token de autenticação é válido. O dilema surge porque a validação é assíncrona, e altera o estado do contexto. Com isso, tenho duas renderizações: a primeira, retornando “null” e, a segunda, o valor real.
Considerei alternativas, como usar um outro estado para indicar que o método assíncrono está carregando, assim, evito que a validação no middleware ocorra na primeira renderização, onde o valor ainda é nulo. Deu certo, mas acho que não é o ideal! É importante que o contexto seja atualizado na mudança de estado do “user”, mas estou incerto se duas renderizações são realmente necessárias para esse tipo de validação, onde só preciso saber se o token é válido u não.
Inicializar o estado do “user” com o valor real, em vez de “null”, é uma opção, mas isso resultaria em múltiplas solicitações à API a cada atualização de estados do contexto, dada ausência de useEffect.
O primeiro retorno do contexto, e o segundo, após o método assíncrono:
Como está ocorrendo:
const RoutesApp = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/home" element={<RequireAuth><Home /></RequireAuth>} />
<Route path="/login" element={<Login />} />
<Route path="*" element={<Navigate to="/home" />} />
</Routes>
</BrowserRouter>
);
};
export default RoutesApp;
--------------------------------------------------
export const RequireAuth = ({ children }: { children: JSX.Element }) => {
const auth = useAuth(); // Hook by Auth Context
if (!auth.user) {
return <Navigate to="/login" />
}
return children;
};
--------------------------------------------------
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const api = useApi();
useEffect(() => {
validToken()
}, []);
...
const validToken = async () => {
const storageData = localStorage.getItem("authToken");
if (storageData) {
const data = await api.validateToken(storageData);
if (data.user) {
setUser(data.user);
}
}
}
return (
<AuthContext.Provider value={ user, ...}>
{children}
</AuthContext.Provider>
);
}