lisavanmansom / dropandheal-react

https://dropandheal-react.vercel.app/
0 stars 0 forks source link

Case study React #9

Open lisavanmansom opened 1 month ago

lisavanmansom commented 1 month ago

Case study React

In deze issue documenteer ik mijn bevindingen van react en staan voorbeelden hoe ik dat heb uitgewerkt. In deze issue staat o.a QuickStart React, mappenstructuur en code splitting.

bronnen lijst:

lisavanmansom commented 1 month ago

React case study

Wat is react?

React (ook wel React.js of ReactJS genoemd) is een Javascriptbibliotheek om gebruikersinterfaces mee te bouwen. React werd in 2011 door Meta ontwikkeld vanuit de behoefte om de code van grote webapplicaties beter beheersbaar te maken. Het was in eerste instantie een intern project en werd gebruikt voor het Facebook- en Instagramplatform. In 2013 introduceerde Meta React aan het publiek en maakte er een opensourceproject van. Sindsdien groeit het gebruik van React en wordt de bibliotheek door meer dan één miljoen websites gebruikt, waaronder grote namen als Netflix en Uber. React wordt op GitHub onderhouden door Meta en een community van individuele ontwikkelaars en bedrijven.

Start a New React Project

React has been designed from the start for gradual adoption. You can use as little or as much React as you need. Whether you want to get a taste of React, add some interactivity to an HTML page, or start a complex React-powered app, this section will help you get started.

Quick start

npx create-react-app my-app
cd my-app
npm start

When you’re ready to deploy to production, running npm run build will create an optimized build of your app in the build folder.

Creating an app methods options

npx (runner tool):

npx create-react-app my-app

npm:

npm init react-app my-app

yarn:

yarn create react-app my-app

Difference between NPM and NPX

While NPM is used as a package manager, NPX, on the other hand, is used to execute Javascript packages.

NPM stands for Node Package Manager. It is a Javascript package manager and the default package manager for Node projects. NPM is installed when NodeJS is installed on a machine. NPX stands for Node Package eXecute. It is simply an NPM package runner. It allows developers to execute any Javascript Package available on the NPM registry without even installing it. NPX is installed automatically with NPM version 5.2.0 and above.

Image

Conclusion

NPM is a package manager used to install, update or remove packages and dependencies your project requires. NPX is an NPM package used to execute any package on the NPM registry directly without installing it.

Folder structure

After creation, your project should look like this:

my-app/
  README.md
  node_modules/
  package.json
  public/
    index.html
    favicon.ico
  src/
    App.css
    App.js
    App.test.js
    index.css
    index.js
    logo.svg

For the project to build, these files must exist with exact filenames:

You can delete or rename the other files. You may create subdirectories inside src. For faster rebuilds, only files inside src are processed by webpack. You need to put any JS and CSS files inside src, otherwise webpack won’t see them.

lisavanmansom commented 1 month ago

Mappen structuur / routes aanmaken

Folder structure

After creation, your project should look like this:

my-app/
  README.md
  node_modules/
  package.json
  public/
    index.html
    favicon.ico
  src/
    App.css
    App.js
    App.test.js
    index.css
    index.js
    logo.svg

For the project to build, these files must exist with exact filenames:

You can delete or rename the other files. You may create subdirectories inside src. For faster rebuilds, only files inside src are processed by webpack. You need to put any JS and CSS files inside src, otherwise webpack won’t see them.

Documentatie mappen structuur / routes

Best Practices

Understanding the components

Additional Features

Conclusion

Using react-router-dom makes it straightforward to create multi-page React applications with dynamic routing capabilities. You can set up a robust navigation system that enhances the user experience without full page reloads.

Uitwerking mappen structuur / routes

npm install react-router-dom

package.json code:

{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^6.27.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },

Index.js code:

import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Setup pages

import React from 'react';

const introductionT1 = () => {
  return (
    <div>
      <h2>introduction1</h2>
    </div>
  );
};

export default introductionT1;

Mappen structuur / 2

Is there a recommended way to structure React projects? React doesn’t have opinions on how you put files into folders. That said there are a few common approaches popular in the ecosystem you may want to consider.

Grouping by features or route example

One common way to structure projects is to locate CSS, JS, and tests together inside folders grouped by feature or route.

common/
  Avatar.js
  Avatar.css
  APIUtils.js
  APIUtils.test.js
feed/
  index.js
  Feed.js
  Feed.css
  FeedStory.js
  FeedStory.test.js
  FeedAPI.js
profile/
  index.js
  Profile.js
  ProfileHeader.js
  ProfileHeader.css
  ProfileAPI.js

Grouping by features or route

folder structure:

intro-task/
  task1.js
  task2.js
  task3.js
  task4.js
  task.css
  task.test.js

task.js example:

import './task.css';
import React from 'react';
import { Link } from 'react-router-dom';

function Task2() {
  return (
    <div>
      <h1>Task 2 Page</h1>
      <Link to="/task1">Go to Task 1</Link>
      <Link to="/task3">Go to Task 3</Link>
    </div>
  );
}

export default Task2;

task.test.js

import { render, screen } from '@testing-library/react';
import Task1 from './task1';
import Task2 from './task2';
import Task3 from './task3';
import Task4 from './task4';

test('renders learn react link', () => {
  render(<>
          <Task1/>
          <Task2/>
          <Task3/>
          <Task4/>
        </>);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});
lisavanmansom commented 1 month ago

Code Splitting / components

Instead of downloading the entire app before users can use it, code splitting allows you to split your code into small chunks which you can then load on demand. Code-splitting your app can help you “lazy-load” just the things that are currently needed by the user, which can dramatically improve the performance of your app. While you haven’t reduced the overall amount of code in your app, you’ve avoided loading code that the user may never need, and reduced the amount of code needed during the initial load.

Route-based code splitting

A good place to start is with routes. Most people on the web are used to page transitions taking some amount of time to load. You also tend to be re-rendering the entire page at once so your users are unlikely to be interacting with other elements on the page at the same time.

Here’s an example of how to setup route-based code splitting into your app using libraries like React Router with React.lazy.

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  </Router>
);

React.lazy

The React.lazy function lets you render a dynamic import as a regular component. React.lazy takes a function that must call a dynamic import(). This must return a Promise which resolves to a module with a default export containing a React component. The lazy component should then be rendered inside a Suspense component, which allows us to show some fallback content (such as a loading indicator) while we’re waiting for the lazy component to load.

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}
lisavanmansom commented 1 month ago

Data fetchen

Data fetchen

Different Ways to Fetch Data in React

1. SWR method

This method is used to fetch data from a server and is used in React. It manages any issues that may arise when obtaining the data and helps you manage its storage. SWR includes useState() and useEffect(), so there is no need to import them.

The advantages of SWR:

How to use SWR to get data:

2. JavaScript Fetch() method

The fetch() method is well-known for retrieving data from APIs. It is recognized as the simplest and most used approach.

The advantages of using the fetch() method:

How to use fetch() to get data:

Inside useEffect(), we fetch our data by sending a request with the API key. The response comes back in JSON (JavaScript Object Notation).

In the return statement, we process the received photos by utilizing a map() function to iterate through each item.

In our specific scenario, we are only interested in the photos. We render them in the browser by displaying them in the main file of the application, or root. The main file could be App.jsx or Index.js.

Data fetchen Uitwerking -- JavaScript Fetch() method

Fetch.jsx

Om data te fetchen maak ik gebruik van een Fetch.jsx component, hier fetch ik data van de API en worden daar article's van gemaakt. Om een taak te renderen maak ik gebruik van map die de task state overschrijft (an array of task object). Ik render de title en de description in de article, voor beide maak ik gebruik van dangerouslySetInnerHTML omdat het in html format is gezet in Directus.

import { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';

const Fetch = () => {
    const [Tasks, setTasks] = useState([]);

    useEffect(() => {
      fetch('https://fdnd-agency.directus.app/items/dropandheal_task')
        .then((res) => res.json())
        .then((data) => {
          console.log(data);
          setTasks(data.data);
        });
    }, []);

    return (
        <section>
            {Tasks.map((task) => (
                <article key={task.id}>
                    <h3>{task.title}</h3>
                    <p dangerouslySetInnerHTML={{ __html: task.description }} />
                    <Link to={`/task/${task.id}`}>View Details</Link> {/* Link to task detail page */} 
                </article>
            ))}
        </section>
    );
}

export default Fetch;

App.jsx

De App.jsx regelt de routing.

import './App.css';
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { Link } from 'react-router-dom';
import TaskDetail from './intro-task/taskDetail';

function App() {
  return (
      <div className="App">
        <h1>Drop & Heal</h1>
        <Link to="/task/1">Introductie Rouwtaken</Link>

        <Routes>
          <Route path="/task/:id" element={<TaskDetail />} /> 
        </Routes>
    </div>
  );
}

export default App;

TaskDetail.jsx

In de TaskDetail geef ik custom elementen mee aan de taken, dit doe ik door gebruik te maken van id === '2' &&. Hierdoor wordt gecheckt of de huidige id bij de huidige taak hoort en daarna worden de custom elementen gerendeerd als het true is. Elke taak staat op een aparte pagina.

import MeshgradBlue from '../components/Meshgrad-blue.jsx';
import MeshgradRed from '../components/Meshgrad-red.jsx';
import MeshgradGreen from '../components/Meshgrad-green.jsx';
import MeshgradPink from '../components/Meshgrad-pink';
import ArrowR from '../components/ArrowR.jsx';
import ArrowL from '../components/ArrowL.jsx';

import './task.css';

import { useState, useEffect } from 'react';
import { useParams, Link } from 'react-router-dom';

const TaskDetail = () => {
    const { id } = useParams();
    const [task, setTask] = useState(null);

    useEffect(() => {
        fetch(`https://fdnd-agency.directus.app/items/dropandheal_task/${id}`)
            .then((res) => res.json())
            .then((data) => {
                setTask(data.data); 
            });
    }, [id]);

    if (!task) {
        return <div>Loading...</div>; // Loading state aanpassen
    }

    return (
        <section>
            <h1>Introductie rouwtaken</h1>
            <h2>Rouwtaak</h2>
            <h3>{task.title}</h3>
            <div dangerouslySetInnerHTML={{ __html: task.description }} />

        {/* custom elements based on id */}
        {id === '1' && (
                <div className={`task-detail task-${id}`}>
                    <MeshgradBlue />
                    <Link to="/task/1"><ArrowL /></Link>
                    <Link to="/task/2"><ArrowR /></Link>

                    <div aria-busy="true" aria-describedby="progress-bar"></div>
                    <progress value="50" max="100"></progress>
                </div>
            )}

            {id === '2' && (
                <div className={`task-detail task-${id}`}>
                    <MeshgradRed />
                    <Link to="/task/1"><ArrowL /></Link>
                    <Link to="/task/3"><ArrowR /></Link>

                    <div aria-busy="true" aria-describedby="progress-bar"></div>
                    <progress value="60" max="100"></progress>
                </div>
            )}

            {id === '3' && (
                <div className={`task-detail task-${id}`}>
                    <MeshgradGreen />
                    <Link to="/task/2"><ArrowL /></Link>
                    <Link to="/task/4"><ArrowR /></Link>

                    <div aria-busy="true" aria-describedby="progress-bar"></div>
                    <progress value="70" max="100"></progress>
                </div>
            )}

            {id === '4' && (
                <div className={`task-detail task-${id}`}>
                    <MeshgradPink/>
                    <Link to="/task/3"><ArrowL /></Link>
                    <Link to="/task/4"><ArrowR /></Link>

                    <div aria-busy="true" aria-describedby="progress-bar"></div>
                    <progress value="80" max="100"></progress>
                </div>
            )}
        </section>
    );
};

export default TaskDetail;