После успешного входа в систему, как перемещаться и отображать навигационные ссылки - PullRequest
1 голос
/ 27 мая 2020

После успешного входа в систему я хотел бы отображать следующие ссылки навигации на основе следующих привилегий. Отображение Profile навигационной ссылки на основе res.data.loginData [0] .privilege === "PLAYER". Отображать ссылку Profile, Register nav, если res.data.loginData [0] .privilege === "ADMIN".

Без входа в систему, когда пользователь обращается к сайту, мы должны отображать только Home, Login and Aboutus страницы.

Поскольку я новичок в этой сфере, я не уверен, что это реализовано таким образом, пожалуйста, сообщите. enter image description here

Login.js

const handleSubmit = (e) => {
    e.preventDefault()
    const fetchData = async () => {
      try {
        const res = await Axios.post('http://localhost:8000/service/login', { email , password });
        setLoginData(res.data.loginData); 
          if (email === res.data.loginData[0].email && password === res.data.loginData[0].password) {
            setError(false);
            setHelperText('Login Successfully !');
            if(res.data.loginData[0].privilege === "PLAYER"){

            }
        } else {
            setError(true);
            setHelperText('Incorrect Email or Password..!')
          }
      } catch (e) {
        console.log(e);
      }
    }
    fetchData();
  };

Navigation.js

const Navigation = () => {
    return (
        <div className="App">
            <div className="wrapper">
                <nav className="siteNavigation_nav_links">
                    <NavLink className="mobile_register_link" to="/">Home</NavLink>
                    <NavLink className="mobile_register_link" to="/profile">Profile</NavLink>
                    <NavLink className="mobile_register_link" to="/register">Register</NavLink>
                    <NavLink className="mobile_login_link" to="/login">Login</NavLink>
                    <NavLink className="mobile_login_link" to="/aboutus">About us</NavLink>
                </nav>
            </div>
        </div>
    );
}

export default Navigation;

App.js

var ReactDOM = require('react-dom');
const App = () => ( <BrowserRouter>
  <>
    <Navigation />
    <Switch>
      <Route exact path="/" component={Home} />
      <Route path="/profile" component={Profile} />
      <Route path="/register" component={Register} />
      <Route path="/login" component={Login} />
      <Route path="/aboutus" component={Aboutus} />
    </Switch>
  </>
</BrowserRouter>)
ReactDOM.render(React.createElement(App, null), document.getElementById('root'));

export default App;

1 Ответ

1 голос
/ 28 мая 2020

TL; DR: Условно отобразите NavLinks в компоненте Navigation. Оформить заказ в песочнице .


НЕКОТОРЫЙ контекст.

@ soccerway, поскольку на этот вопрос можно ответить с помощью того же подхода в ранее ответил на один , для краткости я переработал эту песочницу кода с небольшими изменениями, чтобы попытаться воспроизвести ваш случай со следующими предположениями ...

  1. Похоже, вы используете локальное состояние с useState при входе в систему на основе этого оператора setLoginData(res.data.loginData), но поскольку ваш компонент может быть отключен от панели навигации, учитывая тот факт, что у вас нет другой панели навигации или панели инструментов и ваши пользователи обязательно будут легко перемещаться вперед и назад, размонтирование этого компонента приведет к тому, что приложение потеряет это состояние. Намного лучше использовать более высокое управление состоянием, сохраняя данные Auth и Privilege между страницами. Вы можете использовать React's Context и получить к нему доступ с помощью useContext hook или использовать Redux и обернуть данные сеанса вокруг всего приложения. После входа пользователя в систему сохраните состояние приложения в контексте или в магазине и извлеките его в любом компоненте, который должен иметь это разрешение / условие привилегии. В моем случае я использую api api контекста и сохраняю идентификатор пользователя в localStorage . (Вы можете использовать любое хранилище сеансов, которое захотите.)

  2. Поскольку у меня нет доступа к вашему api, я создал простой fake Auth API и для покрытия handleSubmit. В AuthProvider я предполагал, что данные, которые вы получаете с сервера в этой строке res.data.loginData[0].privilege === "PLAYER", имеют следующий формат, но это может быть что угодно.

// Sample API FORMAT: Note this is normalized not array like -> loginData[0]
const users = {
  "player-1": {
    id: "player-1",
    username: "Player One",
    // permissions: ["view-profile"], // Alternatively, you could have permission logic
    privilege: "PLAYER" // Fetched by => res.data.loginData[0].privilege === "PLAYER"
  },
  "admin-1": {
    id: "admin-1",
    username: "Admin One",
    // permissions: ["view-profile", "register-user"],
    privilege: "ADMIN"
  }
};

// NOTE: The authenticated user is saved in context as currentUser,
// and the login state saved as isLoggedIn 

// Sample login Page
const LoginPage = () => {
  const history = useHistory();
  let location = useLocation();
  const { isLoggedIn, login } = useContext(AuthContext);

  const { from } = location.state || { from: { pathname: "/" } };
  const { pathname } = from;

  let handleSubmit= userId => {
    // login is to the fake Api, but yours could be to an axios server.
    login({ userId, history, from });
  };

  return isLoggedIn ? (
    "you are already logged in"
  ) : (
    <div className="login-btns">
      {pathname !== "/" && (
        <p>You must log in to view the page at {pathname}</p>
      )}
      <button onClick={() => handleSubmit("player-1")}>Player Logs in</button>
      <button onClick={() => handleSubmit("admin-1")}>Admin Logs in</button>
    </div>
  );
};

Поскольку ваши данные легко доступны во всех компонентах через контекст, вы можете использовать их для преобразования привилегий в условия для визуализации компонентов. Tip Назовите условия, относящиеся к визуализируемым вами представлениям, а не к API, поскольку они сильно меняются . Вы можете получить привилегии из контекста в зависимости от того, какой компонент-потомок вы будете sh для условного рендеринга следующим образом:

const { currentUser, isLoggedIn } = useContext(AuthContext);
const privilege = currentUser?.privilege || [];

// Create View conditions based on the privilages. You can be fancy all you want :)
const canViewProfile = privilege === "PLAYER" || privilege === "ADMIN";
const canRegisterUser = privilege === "ADMIN";

Вы можете использовать этот logi c непосредственно в своем Navigation компоненте, но шансы высоки , некоторые маршруты и коммутаторы будут зависеть от этого logi c для условного перенаправления. Так что лучше избегать повторений, хранить их в родителях братьев и сестер или даже вычислять их в контексте / хранилище. (Совет: Попытка поддерживать одно и то же связанное состояние во многих разных местах укусит, особенно без TypeScript ).

В моем случае я передаю условия в Navigation и Pages через реквизит. См. AuthedComponents ==== to your App component ниже


// This is similar to your App component
const AuthedComponents = () => {
  const { currentUser, isLoggedIn } = useContext(AuthContext);
  const privilege = currentUser?.privilege || [];

  // Generate conditions here from the privilages. You could store them in the context too
  const canViewProfile = privilege === "PLAYER" || privilege === "ADMIN";
  const canRegisterUser = privilege === "ADMIN";

  return (
    <Router>
      <div>
        <h1>{` ⚽ Soccerway `}</h1>
        <UserProfile />

       {/* Pass the conditions to the Navigation. */}
        <Navigation
          isLoggedIn={isLoggedIn}
          canViewProfile={canViewProfile}
          canRegisterUser={canRegisterUser}
        />

        <hr />

        <Switch>
          <Route path="/login">
            <LoginPage />
          </Route>
          <Route path="/about-us">
            <AboutUsPage />
          </Route>

          {/* You can conditionally render hide these items from the tree using permissions */}
          <Route path="/profile">
            {/* Passed down the conditions to the Pages via props to be used in redirection */}
            <ProfilePage canViewProfile={canViewProfile} />
          </Route>
          <Route path="/register-user">
            <RegistrationPage canRegisterUser={canRegisterUser} />
          </Route>

          <Route path="/">
            <HomePage />
          </Route>
        </Switch>
      </div>
    </Router>
  );
};

В компоненте «Навигация» используйте isLoggedIn prop, чтобы отобразить элемент входа NavLink или (страницы профиля и регистрации), поскольку они являются взаимоисключающими. Условно отображать ссылки NavLink на основе привилегий с вычисленными реквизитами.

/* You could get these props from the auth context too... if you want */
const Navigation = ({ isLoggedIn, canViewProfile, canRegisterUser }) => (
  <ul className="navbar">
    <li>
      <NavLink exact to="/" activeClassName="active-link">
        Home
      </NavLink>
    </li>
    {/* Check if the User is Logged in: Show the Login Button or Show Other Nav Buttons */}
    {!isLoggedIn ? (
      <li>
        <NavLink to="/login" activeClassName="active-link">
          Login
        </NavLink>
      </li>
    ) : (
      // Now, here consitionally check for each permission.
      // Or you could group the different persmissions into a user-case
      // You could have this as s seperate navbar for complicated use-cases
      <>
        {canViewProfile && (
          <li>
            <NavLink to="/profile" activeClassName="active-link">
              Profile
            </NavLink>
          </li>
        )}
        {canRegisterUser && (
          <li>
            <NavLink to="/register-user" activeClassName="active-link">
              Register
            </NavLink>
          </li>
        )}
      </>
    )}
    {/* This is a public route like the Home, its viewable to every one  */}
    <li>
      <NavLink to="/about-us" activeClassName="active-link">
        AboutUs
      </NavLink>
    </li>
  </ul>
);

В компонентах, если пользователь не соответствует разрешениям / привилегиям, принудительно перенаправить их на страницу входа.


// Example usage in the Profile Page
const ProfilePage = ({ canViewProfile }) => {
  return canViewProfile ? (
    <>
      <h2>Profile</h2>
      <p>Full details about the Player</p>
    </>
  ) : (
    <Redirect from="/profile" to="/login" />
  );
};

...