Having just completed my first ever Chingu voyage, I wanted to document my experience and the process that went into coding with a team of people scattered around the world.
I joined Chingu after hearing about it at a Coding Meetup in London. I had been teaching myself how to code and was building solo projects to practice, but realised I was missing out on a key part of working as a developer — collaborating within a team.
I signed up, and a month later was accepted onto the programme. After completing the prerequisites (a solo project & a pair programming session) I was assigned to my first ever Chingu team. Using Meeting For Good to work out everyone’s availabilities (including their timezones), we arranged our first Discord meeting.
After discussing a few ideas, we settled on cloning the landing page of Flipboard (a news aggregator site) using the News API. The basic MVP was a responsive grid of news articles that would change based on menu categories and search results. We decided that on top of wanting to create something cool as a team, another goal was to push ourselves to learn new technologies. We agreed to use React & Bootstrap to build the app, of which most of us had little to no experience in, but we were all eager to dive into them for this project. We gave ourselves a couple of days to read through the documentation, watch a couple of tutorials, and experiment with the code before starting.
The design of the app was completed using Zeplin, and we broke up the site into components using the React guidelines. After setting up our development environment with Create React App, each team member was assigned a static component to build with the help of React Bootstrap. Once the basic skeleton of the page was completed, the next stage was to work on the logic of the site.
State and Lifecycle were the key concepts to focus on, as this is how React renders and updates an app. A React component is able to store a local State and pass down properties (
props) from this State to children components that it renders. If a property in this State is updated at any point, this will trigger a re-render of any component that relies on this property, updating it in the DOM with the new property. LifeCycle methods provide a way to trigger functions or State changes depending on certain conditions. We used
componentDidMount() to make the News API call once the component had been rendered to the DOM, updating the State of the App once the data was received in order to populate our news article grid.
Our menu bar had several category options and a search bar to allow a user to update the news article grid below. One method would have been to trigger a new API call each time a category was clicked or searched, update the App State with the new data and re-render the article grid. We decided though to try out React-router, which would allow us to create routes (e.g
/technology) without configuring a server, and load a new page each time a valid route was searched.
Full disclosure: React-router was most likely overkill (and possibly less efficient render-wise) for what would have essentially been a Single-Page Application, but it was a useful package to learn and keep in mind for future projects. It was also a nice touch that you could load different versions of our site depending on the URL.
We created a router that would load the App each time a new route was accessed, with different
props specific to that route. The menu had links to these different routes, and once clicked, would load the App page with new
props. This would render the components and make a News API call based on the specific
props of that route.
This all seemed pretty straightforward until it came to configuring the search bar. When forms are submitted, their default action is to cause a page refresh and redirect to a URL that you have defined in the form. One of the great things about React-router is that you can create a
<Link /> that loads a new route without refreshing the page. Luckily, withRouter allows you to inject the browser’s history object into a Component as a property, which means you can access and modify this object. Using this, we were able to push a
/search URL to the browser’s history (including the search query that the user entered e.g
/search?q=politics), which would then change and load the URL of the browser to this route without a page refresh.
From here there was one more issue we faced. The
/search route was setup so that the search query was passed as a
prop to the App, which in turn was passed to the News API function to make the relevant search. However, if the search query changed whilst still on this route (e.g
/search?q=sport), React-router would not see this as a different route and so would not load a new page using this different query. An initial solution was to use
componentDidUpdate() to check if the query in the URL had changed, and then re-render the grid accordingly. However, a simpler solution was to set the key of the search route App component to the search query, so if the query were altered, this would also change the key. React uses keys to keep track of components. If a component’s key changes, React sees it as a new component and re-mounts it.
Features & Bugs
The MVP was finally up and running, so we set about fixing some issues and adding a couple of features.
One was an Infinite Scroll so that the user could scroll down to load more articles. We initially used react-infinite-scroll-component, but it stopped working when changing to a new route unless the browser window was scrolled to the top (if the user scrolled down and linked to a new route then it wouldn’t work, and setting
window.scrollTo(0,0) didn’t help either). Switching to react-infinite-scroller solved the issue, so that saved us from having to waste time trying to debug or build the feature from scratch.
The other feature was to add a share button to each news article so that the user could post it on social media. Both react-share and the Bootstrap modal component made this relatively simple to implement.
Netlify Lambda Functions
One problem with making HTTP requests on a front-end app is that you can’t hide private API keys when you deploy the site, even when privately setting environment variables on your hosting platform (they become visible in the browser’s developer tools in the network tab). Luckily Netlify Lambda Functions provided a server-side solution without having to build a server ourselves to hide the keys. This article alongside this one were both helpful in learning how to convert our News API function to a Lambda Function and modify our front-end to make a request to the Lambda Function route.
However, once the Lambda Functions were minified an error occurred. This was due to our use of the News API Node.js Client Library. This library depends on the client-side Fetch API, but to use it server-side requires an additional dependency to be installed. Without this, Fetch was not defined as a function, and so we couldn’t use the library.
Instead we switched to Axios to handle the requests, and this actually helped later with another React issue.
Using asynchronous code can cause memory leaks in React. This happens when you call a function that doesn’t immediately return (e.g
XMLHttpRequest())and then you unmount the component that called it. The function will finish executing later, even though the component no longer exists. The best practice is to cancel any asynchronous functions when you unmount a component, using the conveniently named LifeCycle method
Axios provides an easy way to cancel requests, so if the user switched to a new route before any data returned, we were able to cancel the old request before unmounting and mounting a new component with a new request.
Side note: It was important to use the second cancel method in the documentation with the
CancelToken constructor, as the first method prevented any new requests from being made after cancelling the old one.
After battling with Netlify configuration settings, finally our site was live.
You can see the MVP here: https://chingu-news.netlify.com/
Our repo here: https://github.com/chingu-voyages/v8-geckos-team-13
As the first time I had built something with a team, this was a really valuable experience for me. It was fun to both learn from other people, and at the same time teach them what I had learnt. Having a group to bounce ideas off of also made solving new problems an easier process.
Clear communication is always an important factor in a team, and understanding your team members and the way they work was crucial to that. Setting well-defined goals was also vital in helping us to stay motivated and move forward each week with our project.
I would recommend the Chingu programme to anyone who wants to accelerate their learning with a hands-on project and improve their technical and soft skills. Even if you feel unsure about your coding level or are nervous about failing, it is a supportive environment where you will learn a lot quickly, whilst strengthening your Googling skills.