MERN stands for MongoDB, Express, React, Node, after the four key technologies that make up the stack. MERN is one of several variations of the MEAN stack (MongoDB Express Angular Node), where the traditional Angular.js frontend framework is replaced with React.js. Follow along and check 66 most common MERN Stack Interview Questions you are most likely will be asked on your next MERN Developer interview.
React creates a virtual DOM. When state changes in a component it firstly runs a "diffing" algorithm, which identifies what has changed in the virtual DOM. The second step is reconciliation, where it updates the DOM with the results of diff.
Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class. With Hooks, you can extract stateful logic from a component so it can be tested independently and reused. Hooks allow you to reuse stateful logic without changing your component hierarchy. This makes it easy to share Hooks among many components or with the community.
props in React?Props are inputs to a React component. They are single values or objects containing a set of values that are passed to React Components on creation using a naming convention similar to HTML-tag attributes. i.e, They are data passed down from a parent component to a child component.
The primary purpose of props in React is to provide following component functionality:
state changes.this.props.reactProp inside component's render() method.For example, let us create an element with reactProp property,
<Element reactProp = "1" />This reactProp (or whatever you came up with) name then becomes a property attached to React's native props object which originally already exists on all components created using React library.
props.reactProp;Below are the advantages of ReactJS:
For example, AngularJS (1.x) approaches building an application by extending HTML markup and injecting various constructs (e.g. Directives, Controllers, Services) at runtime. As a result, AngularJS is very opinionated about the greater architecture of your application — these abstractions are certainly useful in some cases, but they come at the cost of flexibility.
By contrast, React focuses exclusively on the creation of components, and has few (if any) opinions about an application’s architecture. This allows a developer an incredible amount of flexibility in choosing the architecture they deem “best” — though it also places the responsibility of choosing (or building) those parts on the developer.
Replication is the process of synchronizing data across multiple servers.
Replication provides redundancy and increases data availability. With multiple copies of data on different database servers, replication provides a level of fault tolerance against the loss of a single database server.
In some cases, replication can provide increased read capacity as clients can send read operations to different servers. Maintaining copies of data in different data centres can increase data locality and availability for distributed applications. You can also maintain additional copies for dedicated purposes, such as disaster recovery, reporting, or backup.
A higher-order component (HOC) is a function that takes a component and returns a new component. Basically, it’s a pattern that is derived from React’s compositional nature We call them as “pure’ components” because they can accept any dynamically provided child component but they won’t modify or copy any behavior from their input components.
const EnhancedComponent = higherOrderComponent(WrappedComponent);HOC can be used for many use cases as below,
Primarily, hooks in general enable the extraction and reuse of stateful logic that is common across multiple components without the burden of higher order components or render props. Hooks allow to easily manipulate the state of our functional component without needing to convert them into class components.
Hooks don’t work inside classes (because they let you use React without classes). By using them, we can totally avoid using lifecycle methods, such as componentDidMount, componentDidUpdate, componentWillUnmount. Instead, we will use built-in hooks like useEffect .
Below are the list of limitations:
Class Components
Functional Components
Let’s look at some of the key features of Node.js.
All APIs of Node.js library are aynchronous that is non-blocking. It essentially means a Node.js based server never waits for a API to return data. Server moves to next API after calling it and a notification mechanism of Events of Node.js helps server to get response from the previous API call.
Asynchronous JavaScript, or JavaScript that uses callbacks, is hard to get right intuitively. A lot of code ends up looking like this:
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})See the pyramid shape and all the }) at the end? This is affectionately known as callback hell.
The cause of callback hell is when people try to write JavaScript in a way where execution happens visually from top to bottom. Lots of people make this mistake! In other languages like C, Ruby or Python there is the expectation that whatever happens on line 1 will finish before the code on line 2 starts running and so on down the file.
When a component’s props or state change, React decides whether an actual DOM update is necessary by comparing the newly returned element with the previously rendered one. When they are not equal, React will update the DOM. This process is called reconciliation.
Sharding is a method for distributing data across multiple machines. MongoDB uses sharding to support deployments with very large data sets and high throughput operations. MongoDB supports horizontal scaling through sharding. MongoDB shards data at the collection level, distributing the collection data across the shards in the cluster.
return callback();
//some more lines of code; - won't be executed
callback();
//some more lines of code; - will be executedOf course returning will help the context calling async function get the value returned by callback.
function do2(callback) {
log.trace('Execute function: do2');
return callback('do2 callback param');
}
var do2Result = do2((param) => {
log.trace(`print ${param}`);
return `return from callback(${param})`; // we could use that return
});
log.trace(`print ${do2Result}`);Output:
C:\Work\Node>node --use-strict main.js
[0] Execute function: do2
[0] print do2 callback param
[0] print return from callback(do2 callback param)You should consider embedded documents (subdocuments) for:
one-to-few (not many, not unlimited). For unlimited use case, you should start considering separating subdocuments into another collection.No.
One of the great things about relational database is that it is really good at keeping the data consistent within the database. One of the ways it does that is by using foreign keys. A foreign key constraint is that let's say there's a table with some column which will have a foreign key column with values from another table's column.
In MongoDB, there's no guarantee that foreign keys will be preserved. It's upto the programmer to make sure that the data is consistent in that manner. Constraints can not be enforced by MongoDB either. It can't even enforce a specific type for a field, due to the schemaless nature of MongoDB.
Take a look at the code below:
class MyComponent extends React.Component {
constructor(props) {
// set the default internal state
this.state = {
clicks: 0
};
}
componentDidMount() {
this.refs.myComponentDiv.addEventListener('click', this.clickHandler);
}
componentWillUnmount() {
this.refs.myComponentDiv.removeEventListener('click', this.clickHandler);
}
clickHandler() {
this.setState({
clicks: this.clicks + 1
});
}
render() {
let children = this.props.children;
return (
<div className="my-component" ref="myComponentDiv">
<h2>My Component ({this.state.clicks} clicks})</h2>
<h3>{this.props.headerText}</h3>
{children}
</div>
);
}
}Given the code defined above, can you identify two problems?
constructor(props) {
super(props);
// ...
}addEventListener()) is not properly scoped because ES2015 doesn’t provide autobinding. Therefore the developer can re-assign clickHandler in the constructor to include the correct binding to this:constructor(props) {
super(props);
this.clickHandler = this.clickHandler.bind(this);
// ...
}In MongoDB, an operation on a single document is atomic.
Because you can use embedded documents and arrays to capture relationships between data in a single document structure instead of normalizing across multiple documents and collections, this single-document atomicity obviates the need for multi-document transactions for many practical use cases.
For situations that require atomicity of reads and writes to multiple documents (in single or multiple collections), MongoDB supports multi-document (distributed) transactions.
Node.js, in its essence, is a single thread process. It does not expose child threads and thread management methods to the developer. js does spawn child threads for certain tasks such as asynchronous I/O, but these run behind the scenes and do not execute any application JavaScript code, nor block the main event loop.
If threading support is desired in a Node.js application, there are tools available to enable it, such as the ChildProcess module.
The thing with node.js is that everything runs concurrently, except for your code.
So, what that means is that there are actually lots of threads running inside Node.js virtual machine (or a thread pool if you wish), and those threads are utilized whenever you call an async function like performing i/o operations on files, accessing databases, requesting urls, etc.
However, for your code, there is only a single thread, and it processes events from an event queue. So, when you register a callback its reference is actually passed to the background worker thread, and once the async operation is done, new event is added to the event-queue with that callback
When Node gets I/O request it creates or uses a thread to perform that I/O operation and once the operation is done, it pushes the result to the event queue. On each such event, event loop runs and checks the queue and if the execution stack of Node is empty then it adds the queue result to execution stack.
This is how Node manages concurrency.
Node.js internally uses a single-threaded event loop to process queued events. But this approach may lead to blocking the entire process if there is a task running longer than expected. Node.js addresses this problem by incorporating callbacks also known as higher-order functions. So whenever a long-running process finishes its execution, it triggers the callback associated. Sometimes, it could lead to complex and unreadable code. More the no. of callbacks, longer the chain of returning callbacks would be.
There are four solutions which can address the callback hell problem:
Make your program modular - It proposes to split the logic into smaller modules. And then join them together from the main module to achieve the desired result.
Use async/await mechanism - Async /await is another alternative for consuming promises, and it was implemented in ES8, or ES2017. Async/await is a new way of writing promises that are based on asynchronous code but make asynchronous code look and behave more like synchronous code.
Use promises mechanism - Promises give an alternate way to write async code. They either return the result of execution or the error/exception. Implementing promises requires the use of .then() function which waits for the promise object to return. It takes two optional arguments, both functions. Depending on the state of the promise only one of them will get called. The first function call proceeds if the promise gets fulfilled. However, if the promise gets rejected, then the second function will get called.
Use generators - Generators are lightweight routines, they make a function wait and resume via the yield keyword. Generator functions uses a special syntax function* (). They can also suspend and resume asynchronous operations using constructs such as promises or thunks and turn a synchronous code into asynchronous.
function* HelloGen() {
yield 100;
yield 400;
}
var gen = HelloGen();
console.log(gen.next()); // {value: 100, done: false}
console.log(gen.next()); // {value: 400, done: false}
console.log(gen.next()); // {value: undefined, done: true}like?I want to query something as SQL's like query:
select *
from users
where name like '%m%'How to do the same in MongoDB?
Answer
db.users.find({"name": /.*m.*/})
// or
db.users.find({"name": /m/})You're looking for something that contains "m" somewhere (SQL's '%' operator is equivalent to Regexp's '.*'), not something that has "m" anchored to the beginning of the string.
async/awaitRewrite this code to async/await:
function asyncTask() {
return functionA()
.then((valueA) => functionB(valueA))
.then((valueB) => functionC(valueB))
.then((valueC) => functionD(valueC))
.catch((err) => logger.error(err))
}async function asyncTask() {
try {
const valueA = await functionA()
const valueB = await functionB(valueA)
const valueC = await functionC(valueB)
return await functionD(valueC)
} catch (err) {
logger.error(err)
}
}PureComponent is exactly the same as Component except that it handles the shouldComponentUpdate method for you.
When props or state changes, PureComponent will do a shallow comparison on both props and state. Component, on the other hand, won’t compare current props and state to next out of the box. Thus, the component will re-render by default whenever shouldComponentUpdate is called.
When building a React application, there is often the need for a deeply nested component to use data provided by another component that is much higher in the hierarchy. The simplest approach is to simply pass a prop from each component to the next in the hierarchy from the source component to the deeply nested component. This is called prop drilling.
The primary disadvantage of prop drilling is that components that should not otherwise be aware of the data become unnecessarily complicated and are harder to maintain.
To avoid prop drilling, a common approach is to use React context. This allows a Provider component that supplies data to be defined, and allows nested components to consume context data via either a Consumer component or a useContext hook.
Key and benefit of using it in lists?A key is a special string attribute you need to include when creating lists of elements. Keys help React identify which items have changed, are added, or are removed.
For example, most often we use IDs from your data as keys
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);When you don’t have stable IDs for rendered items, you may use the item index as a key as a last resort:
const todoItems = todos.map((todo, index) =>
<li key={index}>
{todo.text}
</li>
);Note:
There will be a warning in the console if the key is not present on list items.
stream and what are types of streams available in Node.js?A stream is an abstract interface for working with streaming data in Node.js.
Streams basically provide two major advantages over using other data handling methods:
There are 4 types of streams in Node.js:
fs.createWriteStream() lets us write data to a file using streams.fs.createReadStream() lets us read the contents of a file.net.SocketA blocking call causes results to be returned synchronously.
Performing a blocking system call causes the process to enter the blocked state. Control is let back to the process only after the I/O event that is being waited upon occurs.
const fs = require("fs");
const contents = fs.readFileSync("file.txt", "utf8");
// this line is not reached until the read results are in
console.log(contents);Aggregation operations process multiple documents and return computed results. You can use aggregation operations to:
MongoDB provides aggregation operations through aggregation pipelines — a series of operations that process data documents sequentially. An aggregation pipeline consists of one or more stages that process documents:
Consider:
db.orders.aggregate([
// Stage 1: Filter pizza order documents by pizza size
{
$match: { size: "medium" }
},
// Stage 2: Group remaining documents by pizza name and calculate total quantity
{
$group: { _id: "$name", totalQuantity: { $sum: "$quantity" } }
}
])Virtual DOM
Virtual DOM is about avoiding unnecessary changes to the DOM, which are expensive performance-wise, because changes to the DOM usually cause re-rendering of the page. Virtual DOM also allows to collect several changes to be applied at once, so not every single change causes a re-render, but instead re-rendering only happens once after a set of changes was applied to the DOM.
Shadow DOM
Shadow dom is mostly about encapsulation of the implementation. A single custom element can implement more-or-less complex logic combined with more-or-less complex DOM. An entire web application of arbitrary complexity can be added to a page by an import and <body><my-app></my-app> but also simpler reusable and composable components can be implemented as custom elements where the internal representation is hidden in the shadow DOM like <date-picker></date-picker>.
The event loop is what allows Node.js to perform non-blocking I/O operations — despite the fact that JavaScript is single-threaded — by offloading operations to the system kernel whenever possible.
Every I/O requires a callback - once they are done they are pushed onto the event loop for execution. Since most modern kernels are multi-threaded, they can handle multiple operations executing in the background. When one of these operations completes, the kernel tells Node.js so that the appropriate callback may be added to the poll queue to eventually be executed.
useRef and createRef?The difference is:
createRef will always create a new ref. In a class-based component, you would typically put the ref in an instance property during construction (e.g. this.input = createRef()). You don't have this option in a function component. useRef takes care of returning the same ref each time as on the initial rendering.props in ReactJS?Class in Node.js?super(props)?this?try/catch blockRust has been Stack Overflow’s most loved language for four years in a row and emerged as a compelling language choice for both backend and system developers, offering a unique combination of memory safety, performance, concurrency without Data races...
Clean Architecture provides a clear and modular structure for building software systems, separating business rules from implementation details. It promotes maintainability by allowing for easier updates and changes to specific components without affe...
Azure Service Bus is a crucial component for Azure cloud developers as it provides reliable and scalable messaging capabilities. It enables decoupled communication between different components of a distributed system, promoting flexibility and resili...