Я строю SPA с API для рельсов на серверной части и React на интерфейсной. Аутентификация пользователя работает, как нужно, и я получаю состояние пользователя с рельсов. Проблема в том, что когда пользователь входит в приложение, мне нужно вручную обновить sh весь браузер для обновления состояния.
// App.js
function userReducer(state, action) {
switch (action.type) {
case "success": {
return {
...state,
id: action.id,
username: action.username,
email: action.email,
logged_in: action.status,
error: ""
};
}
case "fail": {
return {
...state,
id: "",
username: "",
email: "",
logged_in: false,
error: action.error
};
}
default:
return state;
}
}
// set initial state of the logged in user
const intialUserState = {
id: "",
username: "",
email: "",
logged_in: false,
error: ""
};
export const UserStatus = React.createContext(intialUserState);
function App() {
const [userState, dispatch] = useReducer(userReducer, intialUserState);
// fetch the user's data
function fetchLoggedInUserData() {
axios
.get("http://localhost:3000/api/v1/logged_in", { withCredential: true })
.then(response => {
const { id, username, email, logged_in } = response.data;
if (response.status === 200) {
dispatch({
type: "success",
id: id,
username: username,
email: email,
status: logged_in
});
}
})
.catch(error => {
dispatch({ type: "fail", error: error });
});
}
// when the app loads, check if the user is signed in or not.
// if the user is signed in, then store the user's data into the state
useEffect(() => {
fetchLoggedInUserData();
}, []);
return (
<UserStatus.Provider value={{ userState, dispatch }}>
<Router>
<>
<Switch>
<Route path="/admin" component={Admin} />
<Route path="/" render={props => <Public {...props} />} />
</Switch>
</>
</Router>
</UserStatus.Provider>
);
}
Приведенный выше код работает, как и ожидалось, и я могу сохранить пользователя указать, как вы видите из кода. Проблема в том, что когда пользователь нажимает кнопку «Отправить», я хочу автоматически сохранить пользователя, не обновляя страницу sh. Код ниже взят из Login.js
// Login.js
function signinReducer(state, action) {
switch (action.type) {
case "field": {
return {
...state,
[action.field]: action.value
};
}
case "signin": {
return {
...state,
error: "",
isLoading: true
};
}
case "success": {
return {
...state,
error: "",
isLoading: false
};
}
case "error": {
return {
...state,
isLoading: false,
error: action.error
};
}
}
}
const initialState = {
username: "",
password: "",
isLoading: false,
error: ""
};
function FormMain() {
const [signinState, dispatch] = useReducer(signinReducer, initialState);
const { username, password, isLoading, error } = signinState;
const handleSubmit = async e => {
e.preventDefault();
dispatch({ type: "signin" });
await postUserData();
};
function postUserData() {
axios
.post(
"http://localhost:3000/api/v1/sessions",
{
user: {
username: username,
password: password
}
},
{ withCredentials: true }
)
.then(response => {
if (response.status === 200) {
dispatch({ type: "success" });
}
})
.catch(error => {
// dispatch({ type: "error", error: error.response.data[0] });
});
}
}
Я удалил форму входа из кода выше, так как он становился слишком длинным. Решение может состоять в том, чтобы каким-то образом перевести состояние из Login.js
в App.js
или напрямую обновить состояние App.js
из Login.js
и использовать useEffect
в App.js
, а также обновить состояние без необходимости вручную обновить sh браузер, но я не знаю, как это сделать.