Hire ReactJS Developers: Affordable, Dedicated React Experts in 72 hours
Hire ReactJS developers to accelerate your project's front-end development and enhance user experience. Build dynamic web applications using React Router, Redux, and GraphQL.
Access 100+ expert ReactJS developers, engineers and architects from Flexiple, handpicked through a 5-hour evaluation process.
Clients rate Flexiple React developers 4.8 / 5 on average based on 10,085 reviews.
100+ fast-growing companies love Flexiple!
Team work makes dreamwork. Flexiple helps companies build the best possible team by scouting and identifying the best fit.

“I’ve been pleased with Purab’s performance and work ethics. He is proactive in flagging any issues and communicates well. The time zone difference is huge but he provides a sufficient overlap. He and I work together very well and I appreciate his expertise.”
Paul Cikatricis
UX and Conversion Optimization Lead

“Flexiple has exceeded our expectations with their focus on customer satisfaction! The freelancers are brilliant at what they do and have made an immense impact. Highly recommended :)”

Henning Grimm
Founder, Aquaplot
“Overall Flexiple brought in high-level of transparency with extremely quick turnarounds in the hiring process at a significantly lower cost than any alternate options we had considered.”

Kislay Shashwat
VP Finance, CREO
“Todd and I are impressed with the candidates you've gathered. Thank you for your work so far. Thanks for sticking within our budget and helping us to find strong talent. Have loved Flexiple so far — highly entrepreneurial and autonomous talent.”

William Ross
Co-Founder, Reckit
“The cooperation with Christos was excellent. I can only give positive feedback about him. Besides his general coding, the way of writing tests and preparing documentation has enriched our team very much. It is a great added value in every team.”

Moritz Gruber
CTO, Caisy.io
“Flexiple spent a good amount of time understanding our requirements, resulting in accurate recommendations and quick ramp up by developers. We also found them to be much more affordable than other alternatives for the same level of quality.”

Narayan Vyas
Director PM, Plivo Inc
“It's been great working with Flexiple for hiring talented, hardworking folks. We needed a suitable back-end developer and got to know Ankur through Flexiple. We are very happy with his commitment and skills and will be working with Flexiple going forward as well.”

Neil Shah
Chief of Staff, Prodigal Tech
“Flexiple has been instrumental in helping us grow fast. Their vetting process is top notch and they were able to connect us with quality talent quickly. The team put great emphasis on matching us with folks who were a great fit not only technically but also culturally.”

Tanu V
Founder, Power Router
Clients
Frequently Asked Questions
View all FAQsWhat is Flexiple's process?
Is there a project manager assigned to manage the resources?
What is Flexiple's model?
What are the payment terms?
- In the monthly model, the invoice is raised monthly and is payable within 7 days of receipt of invoice.
Are there any extras charges?
How does Flexiple match you with the right freelancer?
- Tech fit: Proficiency in the tech stack you need, Recent work on stack, Work in a similar role
- Culture fit: Worked in similar team structure, Understanding of your company's industry, product stage.
13+ skills that React JS Developers at Flexiple are skilled at
ReactJS developers at Flexiple are skilled at Redux, Next.js among others.
Libraries
UI Libraries/Framework
Framework
Testing
How to hire the best ReactJS Developers?
Hire the best ReactJS developers by writing a clear & detailed job description and having a thorough & well-designed interview process.
ReactJS, an open-source JavaScript library released in 2013, is one of the very rare technologies to achieve remarkable growth in the short time that it has been available. Most of ReactJS' popularity comes from the fact that top companies like Facebook and Uber use it to improve their UI issues. A lot of developers have switched to ReactJS because of how easy it is to implement and how faster it gets the job done.If you’re looking to hire React developers for your company, this guide is going to help you find the perfect fit. We’ve included everything you need to know about hiring ReactJS developers.
Let's introduce ReactJS to you
- Origin story: ReactJS was created by Jordan Walke, a software engineer at Facebook. ReactJS’s prototype was called FaxJS, which was deployed on Facebook’s news feed in 2011 and then on Instagram in 2013. It later released as an open-source in May 2013.
- Widely popular: According to the Enterprise JavaScript survey in 2019, 63% of respondents said that they prefer to write code in ReactJS. Out of the 63%, 49% “writes primarily ReactJS code.” The interest for ReactJS hiked from 64.8% in 2018 to 71.7% in 2019, according to a recent State of JavaScript survey of JS developers.
- Used by top companies: ReactJS is widely used by top corporations like Facebook, PayPal, Uber, Instagram, and Airbnb to solve user interface related issues. This credibility has drawn a lot of people to the framework.
- Other trivia: ReactJS also goes by React.js or simply React. People often misunderstand ReactJS as a JavaScript Framework but, according to the official website ReactJS is a JavaScript library for building user interfaces with several characteristics of a framework.
Why is ReactJS widespread?
- Easy and fast to use: Virtual DOM in ReactJS makes the user experience better and developers work faster.
- Efficient re-usability: Permission to reuse ReactJS components significantly saves time.
What are the tools used by ReactJS developers?
These are some of the tools used by ReactJS developers while building the product:
1. Reactide
This is a dedicated integrated development environment for ReactJS development. It is easy to use and has a custom browser simulator. An integrated Node server is also present, which ensures that users aren't dependent on build-in tools or the configuration of the server.
2. React Developer Tools
A browser extension on Chrome, Firefox, and Edge, this tool allows users to ensure that your code is correct. Activating the tool inspects the hierarchies of the ReactJS components, so ReactJS developers are enabled to write clean code.
3. Create ReactJS App
Create React App, introduced by Facebook is an amazing tool for new ReactJS developers. It eases the process of setting up an environment for ReactJS projects as well as optimizes the application so that production is smooth.
4. React Testing Library
Testing code components is an unmissable step while building an app and the React Testing Library is an ideal testing solution for development using ReactJS. It is a lightweight tool and is considered as the standard for testing ReactJS code.
5. BIT
A CLI tool that offers modularity, BIT makes it very easy to share components between various projects. Code sharing and reusing via BIT allows teams to develop components faster and also allows for better maintenance.
6. Storybook
This tool is used to isolate the various UI components and test them, thus making web and mobile app development much faster. Documenting components so that they can be reused and automatic visual testing is also possible.
Writing the job description to hire ReactJS developers
Below are some key points that we at Flexiple have learned through trial and error - a process of filtering through over 15,000 developers. You can use these in your process to hire ReactJS developers.
- Years of software development experience: Be specific about the technology you’re looking for and the number of years of experience needed. A proxy to years of experience can be the number of production-level apps worked on. You'd need to specify if you want junior or senior React developers.
- Type of products built in the past: Based on the type of product you are trying to build - social network, SAAS product, etc. - you can prioritize certain developers over others. You can check for past experience in mobile and web applications. A mobile app developer would also be well versed in React Native.
- Exposure to specific industries: Developers who have built products in certain industries will already know key aspects of laying the foundation for a great product and will be able to predict possible problems.
- Experience working remotely: A developer with past remote work experience is an added advantage as they would have first-hand experience of everything - right from how contracts work to streamlined communication, as well as timelines and deliverables.
- Strong communication: An essential thing to look at when hiring a freelancer is excellent communication skills. Since all the interaction happens online, a freelancer should be able to effectively communicate to ensure a streamlined execution of all work.
Interview Questions to hire ReactJS developers
Now that you have made a quality JD, it can still be tricky to evaluate the skills of your applicants when you hire ReactJS developers. To help you with that, we have created a pool of questions that a good ReactJS developer should be comfortable with.
It is important to note that the ability to answer these questions doesn't imply that you have a top quality candidate. But it definitely is a big step in that direction.
To help you navigate through these questions, we’ve categorized the interview questions in 3 parts:
A. Basic concepts: Includes all basic concepts used across languages but we've focused on their significance in ReactJS. This will give you an understanding of React components and how strong their programming foundation is.
B. Advanced concepts: Includes all concepts that someone with higher expertise around React's component based architecture should know.
C. DS/Algorithm questions: To test the logical capability of the candidate.
A. Basic concepts
While installing npm modules what is the -g and –save-dev flag for?
npm stands for “node package manager”. It is one of the most popular package managers with more than 11 million developers using it worldwide. It is an online repository of Javascript packages and it is also a command-line interface to work with these packages.
-g Flag
While installing npm modules using “npm install”, some of them are installed with a “-g” flag. This stands for global. Generally, an npm module is saved in your local project folder or repository, but in certain cases when we want to save it globally the “-g” flag is used.
One such case is when the module offers some command-line tools. Saving it globally saves its binaries in the path environment variable of the system. This enables you to use the module in your command line.
Example: Installing the package “Nodemon”. Nodemon is a package popularly used while developing Node.js applications, which helps in creating a live server. Traditionally when a node application is running and we want to incorporate changes in the app, we save the changes, stop the app from running and then re-run it. This becomes quite a tedious process especially during the initial phases of rapid development. Nodemon runs a live server which automatically listens for changes and when any change is saved it restarts the application.
If we were to run “npm install nodemon” and then try to run “nodemon node app.js”, we get the following error.
nodemon : The term 'nodemon' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ nodemon node app.js
+ ~~~~~~~
+ CategoryInfo : ObjectNotFound: (nodemon:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
So, if we instead run “npm install nodemon -g”, and then try to run “nodemon node app.js”
[nodemon] 2.0.5
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node node app.js`
server is up
[nodemon] clean exit - waiting for changes before restart
This will start the live server for app.js file.
--save-dev Flag
By default, npm packages which are installed are saved in node_modules as project dependencies. When someone is trying to clone or recreate your project, they would have to download your project’s dependencies. To do this “npm install” is run and all the dependencies which are listed in the package.json are installed.
But not all packages are required for the functioning of the project. Many packages such as those which help with testing aren’t required for its functioning. In such cases, we use –save-dev flag while installing these packages, as this flag adds the package to the project’s development dependencies. So, when someone runs “npm install” to download all the dependencies, the development dependencies don’t get installed.
Example: Installing the “Jest” package. Jest is a Javascript testing framework developed by Facebook, it works with Babel, Typescript, Vue, ReactJS, Node and Angular. It helps in creating test suites and automated test cases, which help in product development.
If I were to run “npm install jest”, then package.json would look like this:
"dependencies": {
"jest": "^26.5.3"
},
"devDependencies": {}
If we were to run it with the --save-dev flag, like this “npm install jest --save-dev”, then package.json would look like this:
"dependencies": {},
"devDependencies": {
"jest": "^26.5.3"
}
What were the major changes brought about in ES6?
Let us first discuss ECMAScript. ECMAScript is a Javascript standard, designed by ECMA international. It is designed to ensure interoperability across different web browsers. It is commonly used for client side scripting, but has also become popular in server side due to its use in Node.js.
The sixth edition of ECMA Script was introduced in June 2015 called ES6. It was later renamed to ES2015. ECMA has made multiple releases and still continues to make new ones, with the latest one being ES2020 (11th edition). But the reason ES6 is popular is because it brought quite a few major changes. We shall highlight some of the key ones which are required to be known:
1) Introduction of Let and Const:
Var is a highly infamous variable used in javascript extensively. It suffers from the lack of restriction on scope of the variable. That is, if a var is defined inside a block, its scope might extend beyond it also. For example:
var variable = 0
if (true) {
var variable = 100
}
{
{
var variable = 1000
}
}
console.log(variable)
The output is 1000, whereas it should be 0 as the console.log lies in the same block as var variable = 0. To put such restrictions on var, let and const were introduced. Let functions similar to var but with much better restrictions on scoping. Here is the same example with let being used in place of var:
let variable = 0
if (true) {
let variable = 100
}
{
{
let variable = 1000
}
}
console.log(variable)
Here the output is 0, as expected.
Const variables are immutable variables. This means that the value of that variable cannot be changed, similar to the “final” keyword in Java. Const also functions similar to let, in terms of the variable scope. However, objects defined as const can alter their object values and keys, but cannot be reassigned.
This is allowed
const obj = {
name: "Flexiple",
city: "Bengaluru"
}
obj.name = "Flexiple"
console.log(obj)
giving an output as : { name: 'Flexiple', city: ‘Bengaluru’ }
Whereas, this is not allowed:
const obj = {
name: "Flexiple",
city: "Bengaluru"
}
obj = {
company: "Flexiple"
}
console.log(obj)
This throws the following error: “TypeError: Assignment to constant variable"
2) Arrow Functions
Arrow made the syntax for function definitions and return statements shorter. It can be considered similar to lambda functions in Java.
Before ES6 function definition looked like this:
func = function() {
return "end"
}
With arrow functions they can be shortened to:
func = () => {
return "end"
}
And if there is a only a return statement, it can be shortened to:
func = () => "end"
The way “this” works also differs in arrow functions and regular functions.
In arrow functions, “this” always represents the object that defined it. Whereas, in a regular function, “this” represents the function that called it.
3. Template Strings
Prior to ES6 you would have had to add variables to strings in this manner:
var url = "http://localhost:3000/id:"+id
Now, using backticks templating can be done like this:
var url = `http://localhost:3000/id:${id}`
Basically, use backticks to declare a string and inside it use a dollar sign along with curly brackets to insert a variable.
4) Default Parameters
There wasn’t a way to declare parameters in a function as default - it would take the default value as 0. Workarounds popularly used, looked like this:
func = function(param1, param2) {
param1 = param1 || 20
param2 = param2 || true
}
With ES6, we can set default parameters in the following way:
func = function(param1 = 20, param2 = true) {
}
5) Destructuring
This makes assigning variable values a lot faster. Before ES6, it would have looked like this:
var req = {
body: {
username: "flexiple",
email: "[email protected]"
}
}
var username = req.body.username
var email = req.body.email
After ES6, it can be shortened to:
var req = {
body: {
username: "flexiple",
email: "[email protected]"
}
}
var { username, email } = req.body
What is the popular open standard file format (like XML) used with javascript and node.js? And what are the popular commands to convert string to that and vice versa?
It is JSON which stands for Javascript Object Notation. It is a lightweight data interchange format. It is easy for humans to read. Even though it has Javascript in its full form, it is language independent.
It’s built on 2 structures:
- Collection of key-value pairs. This is called an object, dictionary, hashmap, associative array, in different languages
- Ordered list of values, This is called an array, list, vector, in different languages
These are universal data structures which is important for a file format which is language independent.
Example of JSON:
{
"flexiple": {
"top": "1%",
"location": "remote"
},
"blog": {
"topic": "engineering",
"title": "What are stable coins and how do they work?"
}
}
This in XML would look like this:
<root>
<blog>
<title>What are stable coins and how do they work?</title>
<topic>engineering</topic>
</blog>
<flexiple>
<location>"remote"</location>
<top>1%</top>
</flexiple>
</root>
Valid JSON
Few of the rules to remember while handling JSON are that:
- Empty objects and arrays are okay
- Strings can contain any unicode character, this includes object properties
- null is a valid JSON value on its own
- All object properties should always be double quoted
- Object property values must be one of the following: String, Number, Boolean, Object, Array, null
- Number values must be in decimal format, no octal or hex representations
- Trailing commas on arrays are not allowed
These are all examples of valid JSON: -
{"name":"John Doe","age":32,"title":"Vice President of JavaScript"}
["one", "two", "three"]
// nesting valid values is okay
{"names": ["John Doe", "Jane Doe"] }
[ { "name": "John Doe"}, {"name": "Jane Doe"} ]
{} // empty hash
[] // empty list
null
{ "key": "\uFDD0" } // unicode escape codes
These are all examples of bad JSON formatting:-
{ name: "John Doe", 'age': 32 } // name and age should be in double quotes
[32, 64, 128, 0xFFF] // hex numbers are not allowed
{ "name": "John Doe", "age": undefined } // undefined is an invalid value
// functions and dates are not allowed
{ "name": "John Doe",
"birthday": new Date('Fri, 26 Jan 2019 07:13:10 GMT'),
"getName": function() {
return this.name;
}
}
Javascript provides 2 methods to encode data structures to JSON and to convert JSON to objects or arrays. These methods are JSON.stringify() and JSON.parse().
JSON.stringify()
It takes a Javascript object or array as input and returns a serialised string form of it.
const obj = {
name: "Flexiple",
city: "Bengaluru"
}
const jsonStr = JSON.stringify(obj)
console.log(jsonStr)
// output is {"name":"Flexiple","city":"Bengaluru"}
JSON.stringify() can take 3 arguments in total, the first one being the data structure. The second argument, called the replacer parameter, can either be a function or an array. It is used to manipulate the properties (keys and values) in JSON.
let cost = {
candy: 5,
bread: 20,
cheese: 100,
milk: 15
}
let func = (key, value) => {
if (value < 15) {
return undefined
}
return value
}
let arr = ['candy', 'bread']
let jsonStrWithFunc = JSON.stringify(cost, func)
console.log(jsonStrWithFunc)
// Output is {"bread":20,"cheese":100,"milk":15}
let jsonStrWithArr = JSON.stringify(cost, arr)
console.log(jsonStrWithArr)
// Output is {"candy":5,"bread":20}
The third argument, called the space parameter, takes in either a number or a string. It is used to control the spacing of the final string by deciding the size of indentation.
let cost = {
candy: 5,
bread: 20,
cheese: 100,
milk: 15
}
let jsonStrWithNum = JSON.stringify(cost, null, 2)
console.log(jsonStrWithNum)
// Output is
// {
// "candy": 5,
// "bread": 20,
// "cheese": 100,
// "milk": 15
// }
let jsonStrWithStr = JSON.stringify(cost, null, 'xx')
console.log(jsonStrWithStr)
// Output is
// {
// xx"candy": 5,
// xx"bread": 20,
// xx"cheese": 100,
// xx"milk": 15
// }
JSON.stringify() is also popularly used for debugging, as trying to see a JSON object using console.log() isn’t always successful
const obj = {
"nest1": {
"ex": "ex",
"nest2": {
"nest3": {
"ex": "ex",
}
}
}
}
console.log(obj)
// Output is { nest1: { ex: 'ex', nest2: { nest3: [Object] } } }
As we can see that after a certain level of nesting the log just displays ‘[Object]’. Therefore, JSON.stringify() can be used to make debugging easier.
const obj = {
"nest1": {
"ex": "ex",
"nest2": {
"nest3": {
"ex": "ex",
}
}
}
}
console.log(JSON.stringify(obj,null,2))
// Output is
// {
// "nest1": {
// "ex": "ex",
// "nest2": {
// "nest3": {
// "ex": "ex"
// }
// }
// }
// }
JSON.parse()
It takes a JSON string and converts it into its respective data structure
const jsonStr = '{"name":"Flexiple","city":"Bengaluru"}'
const obj = JSON.parse(jsonStr)
console.log(obj)
// output is { name: 'Flexiple', city: 'Bengaluru' }
Calling JSON.parse() on invalid JSON string will throw a SyntaxError.
Cloning Objects in Javascript
These 2 functions of JSON can be used together to clone javascript objects.
const obj = {
"prop1": {
"ex": "ex",
"prop2": {
"ex": "ex"
}
}
}
const objCopy = JSON.parse(JSON.stringify(obj))
console.log(objCopy)
// Output is { prop1: { ex: 'ex', prop2: { ex: 'ex' } } }
But this is not recommended, because of multiple reasons:
- It is slower than alternatives
- This works properly only for valid JSON, but not all javascript objects fall in that category
A better alternative for deep cloning objects would be to either use an npm library called ‘lodash’ or write a custom recursive function to do the same. The spread operator can be used for shallow cloning of objects.
B. Advanced concepts
What is a lint? Have you ever worked with one before, if yes which one?
Linting is the automatic checking of source code for programmatic and stylistic errors. Programmatic errors are the errors such as compilation and run time errors. Each company decides to write their code in a certain style and format, this is done for easy maintenance and to provide further structure to the code.
Stylistic errors are those which might compile without an issue but it does not meet the standards set by the company. Apart from stylistic checks, it is able to identify certain types of bugs like those related to variable scope, undeclared variables, global variables and so on.
Linting is done using a lint tool or linter, which is basically a static code analyzer. It is important as it reduces errors and increases the standard of the code. It can greatly benefit early stages of web development and can save time during code reviews and code maintenance.
ESLint
ESLint is one the most popular lints available for Javascript. Let us go into the basics of using ESLint. This is going to the most basic version of ESLint, remember you can install it with different code style plugins as per your choice.
- After setting up your project (that is running ‘npm init’), run ‘npm install eslint --save-dev’.
- After that we run ‘npx eslint --init’ this is used to generate the ‘.eslintrc.json’ file which is the config file for eslint.
- When we are generating a the config file, it asks a bunch of questions to generate it, these are what I’ve chosen:
√ How would you like to use ESLint? · style
√ What type of modules does your project use? · commonjs
√ Which framework does your project use? · none
√ Does your project use TypeScript? · No / Yes
√ Where does your code run? · node
√ How would you like to define a style for your project? · guide
√ Which style guide do you want to follow? · standard
√ What format do you want your config file to be in? · JSON
- It might have some peer dependencies that it wants you to install - install them too.
- Now we come to using the linter. We run ‘npx eslint app.js’ (here app.js is the source js file).
My app.js file looks like this:
const obj = {
"prop1": {
"ex": "ex",
"prop2": {
"ex": "ex"
}
}
}
const objCopy = JSON.parse(JSON.stringify(obj))
console.log(objCopy)
And the output after running ‘npx eslint app.js’ is:
2:1 error Expected indentation of 2 spaces but found 4 indent
2:5 error Strings must use singlequote quotes
2:5 error Unnecessarily quoted property 'prop1' found quote-props
3:1 error Expected indentation of 4 spaces but found 8 indent
3:9 error Unnecessarily quoted property 'ex' found quote-props
3:9 error Strings must use singlequote quotes
3:15 error Strings must use singlequote quotes
4:1 error Expected indentation of 4 spaces but found 8 indent
4:9 error Strings must use singlequote quotes
4:9 error Unnecessarily quoted property 'prop2' found quote-props
5:1 error Expected indentation of 6 spaces but found 12 indent
5:13 error Strings must use singlequote quotes
5:13 error Unnecessarily quoted property 'ex' found quote-props
5:19 error Strings must use singlequote quotes
6:1 error Expected indentation of 4 spaces but found 8 indent
7:1 error Expected indentation of 2 spaces but found 4 indent
11:1 error Trailing spaces not allowed no-trailing-spaces
12:21 error Newline required at end of file but not found eol-last
✖ 18 problems (18 errors, 0 warnings)
18 errors and 0 warnings potentially fixable with the `--fix` option.
Some of the errors can be fixed using the ‘--fix’ flag, so run ‘npx eslint app.js --fix’. This is how my app.js changed after that:
const obj = {
prop1: {
ex: 'ex',
prop2: {
ex: 'ex'
}
}
}
const objCopy = JSON.parse(JSON.stringify(obj))
console.log(objCopy)
Now it does not show any errors on running ‘npx eslint app.js’.
Similarly ESLint can be used to either check syntax, fix bugs, enforce code style and it has a lot of different options to choose from. It supports plugins and allows custom rules also. Apart from ESLint, some of the other popular lints for Javascript are JSLint and JSHint.
How do you work with security vulnerabilities in npm packages?
While working with Javascript frameworks like React.js and Node.js, you will be using a lot of packages, and many packages you use come with their own dependencies. This creates a lot of scope for security vulnerabilities in your project. As many of these packages are open source, vulnerabilities are often discovered and reported to npm. Therefore, a security audit needs to be done for your project.
A security audit is an assessment of package dependencies for known security vulnerabilities. The easiest way to do this would be to run ‘npm audit’. This is automatically run every time ‘npm install package_name’ is run and it shows how many vulnerabilities that package has.
for example on installing axios, this is the output:-
+ [email protected]
added 1 package from 1 contributor, removed 1 package and audited 2154 packages in 16.811s
found 0 vulnerabilities
The ‘npm audit’ submits a description of the dependencies in your project and asks for a list of known vulnerabilities. It checks direct dependencies, devDependencies, bundledDependencies, and optionalDependencies, but does not check peerDependencies. The severity of vulnerabilities are classified into the following types: low, moderate, high and critical.
Let us take a sample project, on running ‘npm audit’, I get a long report of vulnerabilities in it. The final message of the report was this:
found 105 vulnerabilities (104 low, 1 high) in 371 scanned packages
run `npm audit fix` to fix 102 of them.
3 vulnerabilities require semver-major dependency updates.
The long report has description for each vulnerability, which looks something like this:
Low Prototype Pollution
Package lodash
Dependency of mongoose
Path mongoose > async > lodash
More info https://npmjs.com/advisories/1523
- ‘Low’ is the severity of the vulnerability.
- ‘Prototype Pollution’ is the description of the vulnerability
- ‘lodash’ is the name of the package with the vulnerability
- ‘mongoose’ is the package which you have installed, and ‘lodash’ is a dependency of it which has a vulnerability
- ‘Path’ shows the dependency chain: ‘mongoose’ uses ‘async’ which uses ‘lodash’
Many known vulnerabilities are fixed by the package maintainers in the subsequent versions of the package and therefore can be solved by updating the packages. Often times, this is what ‘npm audit fix’ does. I decided to run ‘npm audit fix’:
+ [email protected]
updated 4 packages in 24.002s
fixed 102 of 105 vulnerabilities in 371 scanned packages
1 package update for 3 vulnerabilities involved breaking changes
(use `npm audit fix --force` to install breaking changes; or refer to `npm audit` for steps to fix these manually)
Now, there are 3 vulnerabilities remaining which weren’t addressed by ‘npm audit fix’. This is because the package update involves ‘breaking changes’. In such cases, it is better to not run ‘npm audit fix --force’. What is recommended, is to run ‘npm audit’ again and do a review of the remaining vulnerabilities. Npm often gives suggested steps to fix it, which is what happened in my case:
# Run npm install [email protected] to resolve 3 vulnerabilities
SEMVER WARNING: Recommended action is a potentially breaking change
Low Prototype Pollution
Package minimist
Dependency of nodemon
Path nodemon > chokidar > fsevents > node-pre-gyp > mkdirp >
minimist
More info https://npmjs.com/advisories/1179
This single package ‘minimist’ was leading to 3 vulnerabilities, which had a ‘SEMVER WARNING’ saying that action is potentially breaking change. Above it the recommended update is given: ‘npm install [email protected]’. After running this update, you will have to check whether your project functions properly or not, and then move on to the next vulnerability. I ran ‘npm install [email protected]’ and this package did not show any more vulnerabilities. I ran ‘npm audit’ and got this:
=== npm audit security report ===
found 0 vulnerabilities
in 206 scanned packages
This was an example of how I cleaned up the known security vulnerabilities in a sample project. Similar steps can be used to fix security vulnerabilities in other npm dependent projects.
What is CORS?
CORS stands for Cross Origin Resource Sharing. It is a mechanism that uses additional HTTP headers instructing the browser to allow applications on one origin to accept resources from another origin. A different origin means either different domain, protocol or port.
This is required because browsers, as a security measure, do not allow cross origin HTTP requests initiated from scripts. This is the case with XMLHttpRequest (mostly used method for resource requests) and Fetch API. By default, they allow only same-origin requests.
For example, let’s assume that the front end is hosted on https://a-domain.com and the backend on https://b-domain.com. In such a case, if the front end makes a GET request to https://b-domain.com/posts, it will receive the following error in the console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://b-domain.com
To prevent this CORS is utilised. Basically, additional headers need to be provided - this is the Access-Control-Allow-Origin header. This can take 2 forms of values:
- Access-Control-Allow-Origin : [origin] An example of this would be ‘Access-Control-Allow-Origin: https://a-domain.com. This allows requests only from the specified origin to be able to access resources provided.
- Access-Control-Allow-Origin : * Using the wildcard character (*) means that any site can access the resources provided by your application.
As standard practice, if cross origin requests are being made it is recommended to not use the wildcard character, and instead mention the origin. If the front end is not rendered by the server itself then CORS needs to be used for the client to be able to interact with the server.
In Node.js, you can either directly write the headers for each request or there exists npm packages which plug into frameworks like Express.js. One such example is the ‘cors’ npm package. It is very simple to use:
// declaring app to use express framework
let app = express()
// this is using wildcard character
app.use(cors())
// this is specifying origin
app.use(cors({
origin: 'https://a-domain.com'
}))
// this is specifying cors for specific route
app.get('/', cors(), (req, res) => {
});
In this way CORS can easily be incorporated into your backend server.
What are the vulnerabilities of using cookies? What about the usage of local storage?
Cookies and local storage are primarily used for session management in web application development. What this means is that once the user is authenticated, there needs to be a way for the application to remember the user for a period of time without asking the user to login again.
In an architecture design it is standard to keep the server stateless, but this would mean that the user information cannot be stored on the server. Therefore, the decision was taken to store it on the client. This was originally done using cookies. Cookies are basically a storage facility with the browser, which the client side javascript or the server (using headers) can interact with.
Each item stored in cookies is called a cookie, and each cookie has an expiration time which can be manually set too. The cookie persists in the browser for that duration and is not removed by page refreshes or window being shut. When a client interacts with a server using HTTP requests, then the cookies are also sent along in headers.
The data which is stored in a cookie is generally a token such as a JSON Web Token (JWT). JWT consists of a payload which is used to fetch information about the user. JWT tokens are signed on the server using a secret key. The routes allow only authorized users to check whether the token is present in the cookies. This is the outline of the architecture followed for session management.
Difference between Cookie and Local Storage
Primarily both function in similar ways - i.e. both involve persistent storage in the browser. The differences come in slight nuances of their functioning:
- Local storage does not have the concept of expiration time. So, the developer dealing with it needs to handle the expiration of tokens stored in it. Whereas, the expiration time for cookies can be set while storing the cookie and the browser handles the rest.
- Local storage is not sent with every HTTP request, like a cookie is sent. This reduces load on especially those HTTP requests which are public and do not require to use the token stored.
- The server can directly interact with cookies, whereas only the client side script can interact with local storage.
- Local storage has a much larger storage capacity of 5mb compared to 4kb of cookie. This is primarily because cookies are meant to be read by the server, whereas local storage is meant for the client side to be able to persistently store data.
Vulnerabilities
Local storage
Local storage is accessible only by client-side javascript code. This makes it particularly vulnerable to XSS attacks. XSS (Cross-Site Scripting) attacks are a type of injections in which malicious scripts are injected into otherwise trusted websites due to a vulnerability.
This script then executes on the client’s browser and can access the local storage quite easily. XSS attacks are mainly used to steal cookies, session tokens and other information. After obtaining session tokens they can access protected routes using it. Therefore, storing authentication tokens on local storage is very risky.
Cookies
Cookies function similarly as they can also be accessed by client-side javascript code. They are also vulnerable to XSS attacks, but there can be a further layer of protection added to prevent this.
If the ‘httpOnly’ flag is marked as true while setting cookies then client side javascript cannot access that cookie. This allows only the server side code to interact with it. So this protects it from XSS attacks. However, due to its property of sending a cookie on every request, it gets vulnerable to CSRF/XSRF attacks.
CSRF/XSRF (Cross-Site Request Forgery) attacks are when malicious web apps can influence the interaction between a client browser and a web server that trusts the browser. Therefore, further measures need to be taken like using CSRF tokens and proper use of the Same-Site cookie attribute.
C. Data Structure/ Algorithm
1. Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. An input string is valid if: Open brackets must be closed by the same type of brackets. Open brackets must be closed in the correct order. Note that an empty string is also considered valid.
class ValidParenthesesF {
func isValid(_ s: String) -> Bool {
var stg = [Character]()
for char in s {
if char == "(" || char == "[" || char == "{" {
stg.append(char)
} else if char == ")" {
guard stg.count != 0 && stg.removeLast() == "(" else {
return false
}
} else if char == "]" {
guard stg.count != 0 && stg.removeLast() == "[" else {
return false
}
} else if char == "}" {
guard stg.count != 0 && stg.removeLast() == "{" else {
return false
}
}
}
return stg.isEmpty
}
}
The above code will input 0(false).
2. What will the output of the following code be?
var i = 10;
var f = 5;
var g = 3;
if (i / f / g)
document.write("hi");
else
document.write("hello");
a) hi
b) hello
c) error
d) no output
The answer is A because the floating-point division returns a non zero value = 0.66 which evaluates
to true and outputs ‘hi’.
3. What will the output of the following code be?
var p = 2;
var q = 4;
var r = 6;
if (p > q > r)
document.write("true");
else
document.write("false");
The answer is False. It may look like the output can be true because 6 > 4 > 2 is true, but PHP evaluates $z > $y
first, which returns a boolean value of 1 or true. This value (true or 1) is compared to the
next integer in the chain, bool(1) > $z, which will result in NULL and echo “false.”
Hire ReactJS Developers - Parting Thoughts
As discussed, it isn't easy to find a quality freelance ReactJS developer but this guide makes the process easier for you. To offload the entire hiring process, reach out to us at Flexiple. We've designed a high-quality screening process to find dream developers. You can find the best freelance ReactJS developers here. We've already served over a hundred clients, earning great reviews for the quality of service.
Lastly, to quickly summarize it for you:
- Note your project requirements and hire accordingly. Do not go for the lowest or the highest-paid developer.
- Don’t hire without vetting- consider asking questions right from the basics to advanced to logical questions.
- Look for companies like Flexiple that help you find the perfect fit.
That is everything you need to know if you want to hire ReactJS developers. Happy hiring! :)
Explore our network of top tech talent. Find the perfect match for your dream team.