Implementing SPA via React Router library

devfish·2023년 1월 25일
0

React

목록 보기
2/10

Single Page Applications (SPA) update elements within a web app or site, instead of refreshing the whole page.

Major advantages of SPA include smooth interaction akin to a native app and less network traffic.
They also come with non-trivial downsides: slow loading time (since it downloads all static resources all at once), and Search Engine Optimization (SEO) issues (Googlebot easily indexes the page using HTML/CSS data, and has to deploy a more advanced method for indexing SPAs. Also search engines rank not websites but website pages, but for SPAs all the pages are combined into one which minimizes its chances to get ranked on different keywords.) Alot of resources cover various strategies of overcoming this SEO problem specifically concerning SPA.

Using React's React Router library, we can update the view inside an HTML container by associating specific paths with specific elements/components, and then linking those paths with specific triggers (i.e. navigation icons, text.) You can connect the nav elements with the paths via Link, and specify the Routes inside the HTML element you want to update (the individual Route elements should be grouped inside Routes, then the main div/App component should be wrapped by BrowserRouter.)

First we need to install the react-router library: npm install react-router-dom@^6.3.0

Setting up the Router

Import the router, and wrap the entire root component with the BrowserRouter in the index.js file (best practice)

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter} from 'react-router-dom'; //like this 
import 'bootstrap/dist/css/bootstrap.css';

ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>,
document.getElementById('root'));

Configuring Routes

  • Different page components which exist separately as different .js files are imported into the main App.js
  • Routes are individually set and connected to components inside the HTML container we want to update
  • Case: For routes that are undefined, direct to "*"
    <Route path="*" element={<NotFound />}></Route>
import {React, useState} from 'react';
import './App.css';
import './global-style.css';
import { Routes, Route} from 'react-router-dom';

import Sidebar from './Sidebar';
import Tweets from './Pages/Tweets';
import MyPage from './Pages/MyPage';
import About from './Pages/About';


const App = () => {
  return (
      <div>
        <div className="App">
          <main>
            <Sidebar />
            <section className="features">
            <Routes>
              <Route path="/" element={<Tweets />} />
              <Route path="/about" element={<About />} />
              <Route path="/mypage" element={<MyPage />} />
            </Routes>
            </section>
          </main>
        </div>
      </div>
  );
};

export default App;

Link the navigational elements with the Routes

import React from 'react';
import {Link} from 'react-router-dom';


const Sidebar = () => {
  return (
    <section className="sidebar">
        <Link to ="/"><i className="far fa-comment-dots"></i></Link>
        <Link to ="/about"><i className="far fa-question-circle"></i></Link>
        <Link to="/mypage"><i className="far fa-user"></i></Link>
    </section>
  );
};

export default Sidebar;

useNavigate

  • Returns a function (a react hook) that enables you to navigate programmatically via accessing the React Router history object
  • First assign the function to a variable so that you can pass arguments: const navigate = useNavigate()
    • 1st parameter:
      • pass the address/route value (same type as <Link to>) you want to navigate to, OR
      • the delta you want to go to in the history stack
        (e.g. -1 means back once, -2 back twice, 1 forward once, +2 forward twice)
    • 2nd parameter (optional): {replace, state}
      • false is the default. replace: true means you can't go back (clicking the back arrow in the browser will go back to the main page ("/"))
      • state is where you can pass values while moving between pages
        navigate('/route', {state: {key: value, key: value ....}})
        you can access these values by using useLocation()
const Sidebar = () => {
  const navigate = useNavigate();

  const goBack = () => navigate(-1);
  const goForward = () => navigate(1);

    return (
    <section className="sidebar"> //you can also write, button onclick = {() => {navigate("/about")}} 
        <button onClick={goBack} className="navigate"><i className="far fa-circle-left"></i></button>
        <button onClick={goForward} className="navigate"><i className="far fa-circle-right"></i></button>
        <Link to ="/"><i className="far fa-comment-dots"></i></Link>
        <Link to ="/about"><i className="far fa-question-circle"></i></Link>
        <Link to="/mypage"><i className="far fa-user"></i></Link>
    </section>
  );
};

Application: Conditional Navigation

For instance, navigating to different pages depending on whether the user is logged in or not

import { useNavigate } from "react-router-dom";

function MypageForm() {
  let navigate = useNavigate();

  function handleClick() {
		if(loggedin) navigate('/mypage');
    	else navigate('/login');	
  }

  return <button onClick={handleClick}>myPage</button>;
}

Adding Event Listeners to React Components

  • When you add an event listener, it needs to happen inside a component
  • Use React.useEffect hook to add the event listener only after the component finishes rendering
  • When you return a function in the useEffect callback, it runs when the component unmounts, which can be used to remove teh event listener when the component is no longer mounted!
const App = (props) => {
  const handleKeyDown = (event) => {
    console.log('A key was pressed', event.keyCode);
  };

  React.useEffect(() => {
    window.addEventListener('keydown', handleKeyDown);

    // cleanup this component
    return () => {
      window.removeEventListener('keydown', handleKeyDown);
    };
  }, []);

  return (
    <div className='container'>
      <h1>Welcome to the Keydown Listening Component</h1>
    </div>
  );
};

EventListener for screen resizing

const App = () => {
  React.useEffect(() => {
    window.addEventListener('resize', (e) => {
      // const sidebar =
      if (window.matchMedia("(min-width: 500px)").matches) {
        console.log("Screen width is at least 500px");
      } else {
        console.log("Screen less than 500px");
      }
    })
  }, []);
  return (
    <div className="App">
      <main>
        <Sidebar />
        <Features />
      </main>
    </div>
  );
};

Application in Sidebar (combining useNavigate & EventListener)

const Sidebar = () => {
  const navigate = useNavigate();
  const goBack = () => navigate(-1);
  const goForward = () => navigate(1);

  const handleKeyDown = (e) => {
    if (e.key === "ArrowLeft") goBack();
    else if (e.key === "ArrowRight") goForward();
  }

  React.useEffect(() => {
    window.addEventListener('keydown', handleKeyDown);

    return () => {
      window.removeEventListener('keydown', handleKeyDown);
    }
  })

  return (
    <section className="sidebar">
        <button onClick={goBack} className="navigate"><i className="far fa-circle-left"></i></button>
        <button onClick={goForward} className="navigate"><i className="far fa-circle-right"></i></button>
        <Link to ="/"><i className="far fa-comment-dots"></i></Link>
        <Link to ="/about"><i className="far fa-question-circle"></i></Link>
        <Link to="/mypage"><i className="far fa-user"></i></Link>
    </section>
  );
};

export default Sidebar;

References

profile
la, di, lah

0개의 댓글