{"id":22848404,"url":"https://github.com/feedzai/first-react-app-workshop","last_synced_at":"2025-04-30T04:48:58.520Z","repository":{"id":42665145,"uuid":"171925694","full_name":"feedzai/first-react-app-workshop","owner":"feedzai","description":null,"archived":false,"fork":false,"pushed_at":"2022-03-29T09:10:21.000Z","size":1618,"stargazers_count":5,"open_issues_count":1,"forks_count":3,"subscribers_count":24,"default_branch":"boilerplate","last_synced_at":"2025-04-30T04:48:53.485Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/feedzai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-21T18:45:05.000Z","updated_at":"2024-05-22T12:27:35.000Z","dependencies_parsed_at":"2022-09-08T16:52:00.963Z","dependency_job_id":null,"html_url":"https://github.com/feedzai/first-react-app-workshop","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feedzai%2Ffirst-react-app-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feedzai%2Ffirst-react-app-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feedzai%2Ffirst-react-app-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feedzai%2Ffirst-react-app-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/feedzai","download_url":"https://codeload.github.com/feedzai/first-react-app-workshop/tar.gz/refs/heads/boilerplate","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251644827,"owners_count":21620630,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-13T04:12:07.199Z","updated_at":"2025-04-30T04:48:58.498Z","avatar_url":"https://github.com/feedzai.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Workshop: Building your first React App\n\n\u003cp style='text-align: justify;'\u003eThis training workshop will cover the fundamentals of React. React.js is a an open-source JavaScript library for creating user interfaces with a focus on the UI and has become the tool of choice for easily building dynamic user interfaces.\u003c/p\u003e\n\n## Requirements:\n\n### Using Codesanbox\n\n- Laptop\n- An internet connection\n- [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?style=flat-square\u0026logo=codesandbox)](https://githubbox.com/feedzai/first-react-app-workshop)\n\n### Using your computer locally:\n\n- Laptop\n- Node/NPM (https://nodejs.org/en/download/)\n- Chrome/Edge/Firefox\n- Chrome Extension - React Developer Tools (https://goo.gl/g16a7N)\n- Text editor (https://code.visualstudio.com/)\n\n#### 1 - Installing Node\n\nMake sure you have Node 8.10 or later on your local development machine.\n\n```sh\nnode -v\n```\n\nIf you don’t, install the latest version: [https://nodejs.org/en/](https://nodejs.org/en/).\n\n#### 2 - Running the Project\n\nVerify that everything works by running:\n\n```sh\ngit clone https://github.com/feedzai/first-react-app-workshop\ncd first-react-app-workshop\nnpm install\nnpm start\n```\n\nOpen [http://localhost:3000](http://localhost:3000) to view it in the browser.\n\nIf there are any questions, feel free to email me! joao.dias@feedzai.com\n\n---\n\n## Tutorial Step-by-step\n\n### Your First React App\n\n### Step 1 - Let's have a look around, shall we?\n\nLet's go to the `src` folder and check all the sub-folders there.\n\n- `assets` - This is where all the global styles are\n- `components` - This is where all the react components live\n- `pages` - Like the `components` folder, but for the app pages\n- `services` - This is were the special functions that connect to firebase live\n- `utils` - This is were we setup Firebase\n\nNow let's go to the `public` folder:\n\n- This is a static folder, were we host our `index.html` file.\n  - Notice that we have a little special loader between the `#root` folder.\n  - This is removed once React kicks-in, but it helps out to showcase some content before that happens.\n  - The favicon is an SVG file that adapts itself to dark and light modes.\n\n### Step 2 - Get the app router to work\n\nFirst we need to make the single-page app understand our url structure. Each different url equals a different page. Some urls even support special placeholder characters so that they can be rendered dinamically. To do that, let's go to the `App.js` component.\n\n```jsx\n// src/App.js\n\nfunction App() {\n  return (\n    \u003cdiv className=\"app\" role=\"application\"\u003e\n      \u003cRouter\u003e\n        \u003cRoutes\u003e\n          {/*\u003cRoute path=\"/chat/:person\" element={\u003cConversationPage /\u003e} /\u003e\n          \u003cRoute path=\"/chat\" element={\u003cChatsPage /\u003e} /\u003e\n          \u003cRoute path=\"/\" element={\u003cHomePage /\u003e} /\u003e*/}\n        \u003c/Routes\u003e\n      \u003c/Router\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nNow we need to display the each page in between the `Router` component. So, let's uncomment the code and have a look at it.\n\nEach `Route` component comes from the `react-router` library. They define each page and accept one of our components to display. We can also define a path, which is the section of the url that comes after the domain.\n\nNow, the `/chat` and `/` paths are pretty self-explanatory. But the `/chat/:person` is a litte different. The `:person` bit is sort of a template that we can use later on the app.\n\n```js\n\u003cRouter\u003e\n  \u003cRoutes\u003e\n    \u003cRoute path=\"/chat/:person\" element={\u003cConversationPage /\u003e} /\u003e\n    \u003cRoute path=\"/chat\" element={\u003cChatsPage /\u003e} /\u003e\n    \u003cRoute path=\"/\" element={\u003cHomePage /\u003e} /\u003e\n  \u003c/Routes\u003e\n\u003c/Router\u003e\n```\n\nAfter uncommenting the code we should now be able to see the new rendered pages.\n\n### Step 3 - Get the latest people and show the cards\n\nShow, there are no cards showing, right?\nThat's ok, we're going to take care of that now.\nTo do that, let's first import a special hook from react, called `useEffect`.\n\n```js\n// src/CardsList/index.js\nimport React, { useEffect, useState } from \"react\";\n```\n\nThis `useEffect` hook enables you to perform any type of side-effects on a function component.\nSo, each time a component is mounted, re-renders or unmounts, we can run code inside these hooks.\nThese hooks accept two arguments:\n\n- a callback function\n- an array of dependencies\n\nWe want to subscribe to the `\"people\"` collection from our firebase firestore.\nAnd we can do that once the component mounts, since that subscription will be alive through out the whole lifecycle of the component.\n\nSo, let's use the `getPeople` services function that we've built for you to abstract the part of fetching the data from the server. This function accepts a callback function, so we will use the `allUsers` array to update our component's state.\n\nThere's already a function to do that - `setUsers`.\n\n```jsx\n// src/CardsList/index.js\n\nuseEffect(() =\u003e {\n  // Use the `getPeople` function and update the users state\n  // once the server has responded with a list.\n  const unsubscribe = getPeople((allUsers) =\u003e setUsers(allUsers));\n\n  return () =\u003e {\n    // Since we're simulating a server response with a delay,\n    // we also need to clear our timeout, or else the timeout\n    // would continue to be kept in memory\n    clearTimeout();\n\n    // We also need to remove the firebase subscription\n    unsubscribe();\n  };\n}, []);\n```\n\nStill no cards? That's fine, there's one little bit left.\n\nTo render multiple items in React, we pass an array of React elements. The most common way to build that array is to map over your array of data. Let’s do that in the `renderList` function.\n\n```jsx\n/**\n * Render an array of `Card` components\n *\n * @returns {JSX.Element[]}\n */\nfunction renderList() {\n  // Go through each user and return a `Card` component with the necessary props\n  // 1. Convert the distance in meters to kilometers;\n  // 2. Don't forget the key\n  const listOfUsers = users.map((person) =\u003e {\n    const convertedDistance = (person.distance / 1000).toFixed(1);\n\n    return \u003cCard key={person.name} distance={convertedDistance} person={person} /\u003e;\n  });\n\n  return listOfUsers;\n}\n```\n\nNow the cards should appear! 👌\nPlay with them, swiping left and right.\n\n### Step 4 - Get the bottom buttons and modal showing\n\nLet's also show the bottom buttons by uncommenting the code comment on the `SwipeButtons`, `SpecialModal` components and `handleOnClickButtons` and `handleOnCloseModal` functions.\n\nClick on any of the bottom buttons, and a funny modal should appear! 😉\n\n### Step 5 - Fetch the list of messages from the server\n\nNow, notice on the footer bar, there's a button on the right. That's the messages icon and, if you click on it, it will lead you to the chats page.\n\nSo...let's click on it!\n\nWait, there are no messages? 😱\n\nAgain, it's fine. It's because we haven't fetched the list of messages from firebase.\n\nTo do that, let's go to `Chats` component and do the `useEffect` bit again. This time we use the `getConversations` function\n\n```jsx\n// src/components/Chats/index.js\n\nuseEffect(() =\u003e {\n  const unsubscribe = getConversations((allMessages) =\u003e setMessages(allMessages));\n\n  // When the component unmounts, remove the messages subscription and the fake timeout\n  return () =\u003e {\n    unsubscribe();\n  };\n}, []);\n```\n\nNow that we have an array of messages, let's render them out on the screen!\nTo do that, we will render them by using the `renderMessages` function:\n\n```jsx\nfunction renderMessages() {\n  const list = messages.map((msg) =\u003e {\n    return (\n      \u003cChat\n        key={msg.id}\n        id={msg.id}\n        name={msg.name}\n        message={msg.messages[msg.messages.length - 1].message}\n        timestamp={msg.timestamp}\n        profilePic={msg.profilePicture}\n      /\u003e\n    );\n  });\n\n  return list;\n}\n```\n\nSo, basically, for every message, a `Chat` component.\nThat's great, we should now have a list of messages showing up.\n\n### Step 6 - Send the message data to a specific message screen\n\nWe're almost there to have our basic app running!\nNow the only thing we need to do is, on each click on each message, have some sort of way to send over to the conversation screen some unique identifier that we can use to pick that message out from the full list of messages.\n\nWell, we have!\nNotice that every entry on the `messages` array as an `id` field.\nWe can use that and pass it to the element that receives our click - The `Link` component.\nThe prop is `state` and it accepts an object.\n\n```jsx\n\u003cLink className={styles.chat} to={`/chat/${nameForUrl}`} state={{ id }}\u003e\n  \u003cdiv className={styles.container}\u003e\n    \u003cAvatar className={styles.image} alt={name} src={profilePic} /\u003e\n    \u003cdiv className={styles.details}\u003e\n      \u003ch2 className={styles.title}\u003e{name}\u003c/h2\u003e\n      \u003cp className={styles.message}\u003e{message}\u003c/p\u003e\n    \u003c/div\u003e\n    \u003ctime className={styles.timestamp}\u003e{convertedTimestamp}\u003c/time\u003e\n  \u003c/div\u003e\n\u003c/Link\u003e\n```\n\nNow, a click on the `Link` component will lead us to the `Conversation` page.\nWe can also have a look at the browser's url bar and see that the `:person` template is now being replaced with the users name from the clicked link.\n\nWe now have to reach over to `react-router` and use a special hook (yes, we can create our own custom hooks with react) to get the `location` properties of that page, including the `state`.\n\n```jsx\nimport { useLocation } from \"react-router\";\n\n...\n\n// Inside the component, at the top\nconst location = useLocation();\n```\n\nSo, we have access to the location.\nWe still need to fetch the conversations again, right? It's like we did before.\n\nThere are a couple of differences right now:\n\n- We only want to show one conversation\n- We have access to the clicked id\n\nSo, we need to pick the only conversation that matters. We can do that using the `useEffect` hook, the `getConversation` function and the `find` method for the callback `allMessages` object.\n\n```jsx\nuseEffect(() =\u003e {\n  const unsubscribe = getConversations((allMessages) =\u003e {\n    // Using the `find` method we can pick the message we want\n    // by comparing the source id with our location state id.\n    // If if matches, that's our guy!\n    const conversation = allMessages.find((message) =\u003e message.id === location.state.id);\n\n    // We only update the state if we have an actually usable result\n    if (conversation) {\n      setChat(conversation);\n    }\n  });\n\n  // When the component unmounts, remove the messages subscription\n  return () =\u003e {\n    unsubscribe();\n  };\n}, [location.state.id]);\n```\n\nAnd that's it!\nWe've covered a lot of ground today.\nThere's way more things to learn about React.\nMore hooks, more design patterns, more ways to improve our performance, etc.\n\nBut, there's one more thing...\n\n### 4 - PropTypes\n\nAs your app grows, you can catch a lot of bugs with typechecking. For some applications, you can use JavaScript extensions like Flow or TypeScript to typecheck your whole application. But even if you don’t use those, React has some built-in typechecking abilities. To run typechecking on the props for a component, you can assign the special propTypes property.\n\nImport the `PropTypes` and use them on our components.\n\n```js\nimport PropTypes from \"prop-types\";\n```\n\n## See it run 🚀\n\nYou're at the end of your journey, and you've accomplished a lot. **Congrats, You are awesome!**\n\n---\n\n### Learn More\n\nYou can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).\n\nTo learn React, check out the [React documentation](https://reactjs.org/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeedzai%2Ffirst-react-app-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffeedzai%2Ffirst-react-app-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeedzai%2Ffirst-react-app-workshop/lists"}