Аутентификация React rails - получение состояния пользователя без перезагрузки страницы - PullRequest
0 голосов
/ 04 марта 2020

Я строю 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 браузер, но я не знаю, как это сделать.

1 Ответ

0 голосов
/ 04 марта 2020

Проблема решается созданием нового case до App.js и обновлением этого case из Login.js.

// App.js

function userReducer(state, action) {
  switch (action.type) {
    case "success": {
      return {
        ...state,
        id: action.id,
        username: action.username,
        email: action.email,
        admin: action.admin,
        logged_in: action.status,
        error: ""
      };
    }
    case "fail": {
      return {
        ...state,
        id: "",
        username: "",
        email: "",
        admin: false,
        logged_in: false,
        error: action.error
      };
    }
    case "globalFetch": {
      return {
        ...state,
        id: action.id,
        username: action.username,
        email: action.email,
        admin: action.admin,
        logged_in: action.status,
        error: ""
      };
    }
    default:
      return state;
  }
}

Как видите, случай globalFetch может быть легко передается в Login.js через useContext, а затем обновляется регистр согласно вашему требованию.

// Login.js

function postUserData() {
    axios
      .post(
        "http://localhost:3000/api/v1/sessions",
        {
          user: {
            username: username,
            password: password
          }
        },
        { withCredentials: true }
      )
      .then(response => {
        if (response.status === 200) {
          const { id, username, email, logged_in, admin } = response.data;
          dispatch({ type: "success" });
          state.dispatch({
            type: "globalFetch",
            id: id,
            username: username,
            email: email,
            admin: admin,
            status: logged_in
          });
        }
      })
      .catch(error => {
        // dispatch({ type: "error", error: error.response.data[0] });
      });
  }
 // More code...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...