Awesome packages for React apps, now with hooks!
This article will be an overview of some npm packages that I consider vital for a React application.
Here, we will go step-by-step on data fetching from a network source, state management across application, navigation between pages and tabs, internationalisation with plural and parameters, forms input handling and validation, application feature testing, and some must-have utilities.
I will be showing how we can leverage these packages as we implement a chat application as a real-life example.
Data fetching
An application usually needs to fetch data from a network source so it can be handled and presented to the user.
Here in this project, we will be using the following packages:
- Axios is a promise-based HTTP client. It’s a straightforward solution to make web requests to an endpoint.
This package will help us handle network requests and responses in the next session.
State Management
State management in React application becomes very cumbersome very quickly. As your project scales and, consequently, the number of moving pieces increases, it becomes hard to understand the flow of information.
We need a way to manage state across our React application.
To solve this problem, we will use one of the most used data architectures: Redux, a unidirectional data flow pattern that works pretty well with React way of passing props to children's Components.
In Redux all data flows through the dispatcher as a central hub, that registers actions and send it to this dispatcher. This results in an update to the state of the store. After the store is updated, it broadcast an event declaring that their state has changed, so the views may query the new state and update themselves.
Let’s set up our Redux:
- React Redux is a predictable state container. It helps you store complex states to handle across your application.
- Redux Thunk is a middleware that allows delayed and async operations to Redux — which will be presented next.
- Reselect is a selector library that allows Redux to store the minimal possible state and recompute the state only if its arguments change.
First, we need a rootReducer.js file to combineReducers.
Then, we need a store.js tocreateStore
and export it, applying the redux-thunk middleware:
Now, on App.jsx we import and pass the store to the root of the App inside a<Provider>
, as below:
We will create an action.js and a method togetMessages
that will call axios to make an API request for new messages, and then, dispatch the fetched data:
Our reducer.js will handle the previous state, modify it and return with new information:
To retrieve the data from the store, we will need a selectors.js and create a selector for messages, loading state, and error handling:
To get the list of messages, a useSelector
hook is used from any React functional components:
Note: Redux is a pretty complex library that needs a lot of introduction and tutorials to get started and along with. It also has a lot of different implementations and way of setting up. Please, check the Redux Toolkit website for more information on how to implement it in your project.
Navigation
Building a web/mobile solution most of the time will lead to more than one single page, and we need to handle these routes.
- React Router Dom is a collection of navigational components that compose declaratively with your application. Whether you want to have bookmarkable URLs for your web app or a composable way to navigate in React Native.
In this example, we want the message list to be the home of our application.
We create a component named HomePage and return the MessageListContainer as a component of a <Route/>
, as stated:
Now, to insert routes on our app and navigate between them, we need to wrap our App.jsx with a Router and a Switch containing all application Routes. Our Switch will prevent all routes to be rendered. Instead, it will only render the first matching <Route>
— in this case, the HomePage.
In this example, we have the HomePage and SettingPage:
Let’s suppose that we have a menu with a button that redirects the user to the SettingsPage. On a React functional component, we import the useHistory
hook and calls push to the page:
Note: Router is a big library that has many ways of handling the navigation alongside of pushing new pages. Check the docs for more information.
Internationalization
As your solution scales, you will be dealing with different locations and as part of that, languages.
- React i18next is a powerful internationalization framework for React, which is based on i18next, that allows plurals, formatting, interpolation …
Translations are plain JavaScript objects with key, value pair. Simple as that.
Let’s say we have to translate the upcoming snack bar notification with new messages.
We need to make a new object for every language that our solution will support and include it in resources.
Now, we need to initialize and export our i18n:
Note: this article is for demonstration purpose only and has default language set to english. It will not cover how to change language based on user language detection, for this feature please look up at the i18next docs to see how to change language. To retrieve user location, on React Native using expo and React using web navigator props.
Then, we need to import it on our main index.js to be used on our application:
When using your React functional component, just import useTranslation
hook and pass a key-value parameter to t
.
In this case, we will pass the message count as a second parameter too, inside an object, to allow plural:
Then we will be presented with the following output:
Forms
React does not have a nice way of handling forms validation by default and things can be pretty messy and confuse if you try to implement it all by yourself.
- Formik takes care of the repetitive and annoying form stuff for us: keeping track of values/errors/visited fields, orchestrating validation, and handling submission.
- Yup is a schema builder for value parsing and validation. Yup schema is extremely expressive and allows modeling complex, interdependent validations, or value transformations.
Let’s build a LoginFormContainer to handle guests and logged users.
First, we need to create a validation schema. Here we are using a parameter t
to help us translate validations messages:
Now, with useFormik
hook we pass initialValues of our form, our previously defined validationSchema, and an onSubmit function that will receive our values as a parameter and dispatch the login action to redux:
When all setup is done, we will pass the returned constants from useFormik
to our form, inputs, and button as needed. The return of functional component will look like this:
Testing
Our applications need tests. Unit, integration, end to end… A lot of them.
- React Testing Library is a package to test your React DOM components functionalities without relying on implementation details. This way, you can easily test your components' features without worrying too much about refactors that could break your tests and slow down your team. Using the testing library focus on the supposed output instead of how it was done.
- Jest is a library to create, run, and structure tests. It has many powerful tools that allow you to mock third-party libraries, function calls, react hooks, error callbacks, loading progress.
In this example, the main component renders a list of messages. To do this, the container has the useEffect
hook that will dispatch the getMessages
action to redux on page load and return its stored messages with the useSelector
hook:
Because of this chained behavior, we want to test if this hook is being called on page load, dispatching the action from the messagesActions
:
Now that we had tested our useDispatch
hook and our getMessages
function call, we shall test if after this action is completed, that the redux is sending back the state correctly and the React container is receiving this information through a useSelector
to render that:
Note: Redux testing should be done separately and will not be covered in this article. You should check how to write tests on the Redux documentation. In this example, we will assume that our reducers are correctly setup, tested and will return the data as expected. Here we will only test if the components have been rendered without errors.
Utils
- Lodash makes our lives easier by taking the hassle out of working with some interaction functions — mostly on arrays, objects, and strings — that are not right there out of the box on JavaScript.
Yeah, you are probably thinking that it can easily be created a one-line function that solves the problem.
e.g you need to generate an array upon an informed N value:
But now, imagine that you need a lot of new helpers methods and your team will have to implement them… Your codebase may end up with a lot of generateArray()
functions alike or helper.js/utils.js files.
Lodash by itself is a relatively big library, and, to reduce the final application bundle size, we import only specific functions that are used by our solution, that way we just simply call:
Note: Lodash is a extremely powerful tool that does not limit to the extends of this example, and definitively needs more love and attention.
- Faker is a package focused on generating massive amounts of fake data, as the name defines.
It is a must-have to build factories and use this kind of random data to test your application features and edge cases — instead of a JSON file with a big chunk of static data that will always produce the same result.
We want to generate a lot of random message data to test our messaging application and the best way to do this is to build up a factory:
Now, when we want to populate a very extensive list to test a load more feature on the application, we just import MessageFactory
and use like this:
Conclusion
There are a lot of awesome npm packages out there to help us develop what really matters: the next-level idea. With all those possibilities, we can skip the need to boilerplate non-core features and focus on building the solution we have in mind.
The packages presented in this article were based on personal preference and experience achieved after building a lot of React/React Native projects from scratch. Out there, we have a lot of awesome packages that can do similar things or even better. It’s all about the goal.
Please share this article if you like it 👐.
If you enjoy working on large-scale projects with global impact and if you like a real challenge, feel free to reach out to us at xgeeks! We are growing our team and you might be the next one to join this group of talented people 😉
Check out our social media channels if you want to get a sneak peek of life at xgeeks! See you soon!