jpasquers / interview-prep

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

NextJS

Why nextJS?

Traditionally, to build a react application from scratch you have to include:

  1. Bundling with something like webpack, and transpiling with something like babel
  2. Code splitting
  3. static pre-rendering, and client vs server side rendering

NextJS takes care of all of those.

Routing

A page is a react component exported from a file in the pages directory. The filepath including the filename determines the route that corresponds to that page. e.x.:

  1. pages/index.js -> /
  2. pages/posts/first-post.js -> /posts/first-post

Since it is mapping a component in a file to a route, it obviously must be the default export.

You then leverage Next's Link component to link between pages. Note that this uses client side routing, meaning that there is no browser page reload (no call)

NextJS automatically code splits based on the routes, and pre-loads routes available in existing links from the current page!

Assets

Assets are served from the public/ directory. They are referenced from the root path just like pages

Use the NextJS Image component to load the image (instead of the regular image tag)

This takes care of things like lazy loading, such that images only load when in the viewport.

Styling

NextJS has built-in support for styled-jsx, a library which lets you write CSS in a react component and guarantee that the styling will be restricted to that component.

It also supports CSS Modules, which further prevents naming collisions

Pre-rendering

This means that the HTML page is pre-generated (instead of relying on the javascript to do it at runtime), and then the associated javascript code just makes the page interactable.

This allows you to see content on the page while the javascript is still loading for that page.

There are two forms of pre-rendering

Note NextJS lets you vary your strategy of pre-rendering from page to page... damn

Static Generation

The pre-made HTML files are generated at build time ONCE.

Static Generation With Data

If you have data that you can load once at build time, you can expose it via a getStaticProps method in the corresponding component. NextJS will fetch the data at build time and then pass it as props into the corresponding page when it renders

export default function Home(props) { ... }

export async function getStaticProps() {
  // Get external data from the file system, API, DB, etc.
  const data = ...

  // The value of the `props` key will be
  //  passed to the `Home` component
  return {
    props: ...
  }
}

Server-side rendering

The pre-made HTML files are generated by the server on each request.

Server-side rendering with Data.

Similar to static generation with data, you can load data and automatically pass it to the corresponding component. With getServerSideProps, you will load that data on each request during the generation of the HTML files. (Basically the same concept as above, just when the data is loaded is when the HTML file is created, which in this case is PER request)

export async function getServerSideProps(context) {
  return {
    props: {
      // props for your component
    }
  }
}

Data Fetching

In addition to getStaticProps and getServerSideProps which are pre-rendering data loads, you can also use client-side rendering to get data not needed for the initial page load.

The NextJS team created and recommends using SWR for this.

API Routes

NextJS lets you create Serverless Functions, which are simple lambdas that act like Express request handlers.

These routes should be default exports of files under pages/api. Much like with other pages, the route will match the corresponding file and path name.

SWR

React hook for simple data fetching with cache validation etc. E.x.

import useSWR from 'swr'

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

React

Hooks

Hooks are a feature to allow state and other React features within functional components

Common hooks built into react include:

  1. useState() -> Maintain component state. Returns the value and a mutator.
  2. useEffect() -> Run side effects, such as data fetching.
    • Run after flushing changes to the DOM. Post Render.
    • Comparable to componentDidMount or componentDidUpdate from classes
    • Can return a function to execute on component unmount
    • Able to add a list of items at the end that are 'dependencies'. Aka useEffect will only trigger on re-render if one of those items changes.
  3. useContext() -> Used for reference the current value of a global context
    • Accepts a context object (which came from React.createContext()) and returns the current context value for that object
    • The current context value is determined by the value prop of the nearest <MyContext.Provider> above the component
    • When the context is updated, a re-render is triggered for this component

You can create custom hooks to reuse Stateful logic. Keep in mind that they do not reuse state itself, just the stateful logic. Each invocation is independent.

What is the difference between custom hooks and vanilla JS functions? - When React sees you invoke a function that starts with use, it will automatically allow that function to invoke hooks within it. - In other words, custom hooks can invoke other hooks, and their name beginning with use gives them this power.

General Concepts

Headless CMS

A backend only content repository. Accessible via an API and completely disconnected from the presentation.

AEM has Headless CMS capabilities.

Design and Clean Code Patterns

SOLID - OO Design.

  1. Single Responsibility Principle - "There should never be more than one reason for a class to change"
  2. Open Closed - Pieces of software should be open for extension but closed for modification.
    • Nowadays refers more to the usage of abstracted interfaces, where new implementations can be created and substituted.
  3. Liskov Substitution - "Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it."
    • Enforces the notion of strong behavioral subtyping.
  4. Interface Segregation - "Many client-specific interfaces are better than one general-purpose interface."
    • "When clients depend on methods that they do not use, they become subject to the changes enforced on those methods.
  5. Dependency inversion - "Depend on abstractions not concretions"
    • A specific form of loose coupling

Functional Programming

"Programs are constructed by applying and composing functions"

Key aspects:

  1. Functions are first class citizens: Can be defined as variables, passed as arguments, and so on.
  2. Leverages higher order functions, which can take in other functions as args and return them.
  3. Relies on pure functions, which always return the same output for the same set of input, and have no side affects to external scope.

Common Design Patterns

  1. Delegate - A class which contains a specific other class/interface and implements the same interface. It delegates most behavior to the internal object, but adds functionality as needed.
    • A proxy is a very specific case of a delegate
    • Delegation is an alternative to inheritance, each has paricular benefits.
  2. Adapter - A way to bridge interfaces while maintaining loose coupling.
    • Good example is our OIDC user and application identity interfaces.
  3. Builder - A way to allow the construction of objects with complex varieties that can be created, without 800 contructors
    • Good example is request builders.
  4. Composite - can be thought of as a paired delegate. But importantly implements both interfaces of the objects it composes.
    • AccountIdentityComposite is a good example.
  5. Singleton - Kinda a copout answer imo, but basically an abstraction that guarantees the creation and return of only a single object.

Outdated JS Concepts They Somehow Still Ask About

  1. import vs require
    • import is the standard module syntax for ES6, while require is the module syntax for nodjes.
    • As of v12 (2019), Nodejs enables support for ES6 modules by default. So always use import/export.
  2. closure
    • (Mozilla docs) "A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time."
    • What this means is that an outer function can return an inner function, and that inner function can reference variables created in the outer function, even though the outer function has terminated and that scope has gone away. Effectively, this allows encapsulation because you can create accessors to values without exposing the fields directly.
  3. let vs var
    • var's are scoped to the function body, let's are scoped to the immediate enclosing block. Which lowkey is how it should have been all along.
    • Other minor differences: Let can't be redeclared. Let doesn't assign to window at global scope. Let doesn't hoist.
  4. ()=>{} vs function(){}
    • "Arrow functions establish "this" based on the scope the arrow function is defined in.
      • Thus they are not suitable for bind() etc calls
    • Comparatively legacy functions create their own internal "this"
    • "No matter how or where being executed, this value inside of an arrow function always equals this value from the outer function. In other words, the arrow function resolves this lexically."

About