DEV Community

Axel Mukwena
Axel Mukwena

Posted on

Preparing for Interview at Mobal.io

Notes

Notes to prepare for a Technical Interview for a Software Engineer role at Mobal.io

Introduction

The technical interview is a live coding interview where you are coding the frontend of an app. You have to connect the frontend to a backend server which you can access through an api. You can choose any modern frontend framework that want to complete the task.

Technologies

  1. React.js

Reproduction

Clone the repository

Ensure you have npm installed

$ npm -v
Enter fullscreen mode Exit fullscreen mode

Go to repository directory

$ cd mobal
Enter fullscreen mode Exit fullscreen mode

Install packages

$ npm install
Enter fullscreen mode Exit fullscreen mode

Launch

$ npm start
Enter fullscreen mode Exit fullscreen mode

Creation

Create React app.
Prerequsites: Node >= 14.0.0 and npm >= 5.6

$ npx create-react-app mobal
$ cd mobal
Enter fullscreen mode Exit fullscreen mode

Launch

$ npm start
Enter fullscreen mode Exit fullscreen mode

What? Some interesting readings

Organization and Standards

Notables

  1. --save-dev (only used in the development, not in production)
  2. --save (production dependencies)
  3. --global or -g (used globally i.e can be used anywhere in our local system)

Cnvert strings to paths

  1. Either use
const regex = /[^a-zA-Z0-9]+/g;
const title = "hello123!@#";

// Convert
const path = title.trim().replace(regex, "-").toLowerCase();
Enter fullscreen mode Exit fullscreen mode

Structure

-- src
   -- api
   -- components
   -- styles
   -- pages
   -- utilities
Enter fullscreen mode Exit fullscreen mode

Lints

Install prettier as a Dev dependency

$ npm install prettier --save-dev
Enter fullscreen mode Exit fullscreen mode

Create a .prettierrc at root and

{
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": true,
  "singleQuote": false
}
Enter fullscreen mode Exit fullscreen mode

UI and Styling

Install Material-UI: https://mui.com/material-ui/getting-started/installation/

$ npm install @mui/material @emotion/react @emotion/styled
$ npm install @mui/icons-material
Enter fullscreen mode Exit fullscreen mode

Moment.js to format our time

$ npm install moment
Enter fullscreen mode Exit fullscreen mode

API and Fetch Requests

Axios

$ npm install axios
Enter fullscreen mode Exit fullscreen mode

Update multiple items
Reference: https://stackoverflow.com/a/32101994/8050183

// PATCH /items
const params = [ { id: 1, name: 'foo' }, { id: 2, name: 'bar' } ]
Enter fullscreen mode Exit fullscreen mode
// Post data to api
async function postResource(path, params, handleResponse) {
  const url = API_URL + path;

  // Only send request if there's a authorize cookie set
  // if (!token) return;

  // headers
  const headers = {
    headers: {
      "Content-Type": "application/json",
      Authorization: "token",
    },
  };

  await axios
    .post(url, params, headers)
    .then((response) => {
      handleResponse({ resource: response.data });
    })
    .catch((error) => {
      handleResponse({ resource: null, message: error.message });
      console.log("POST Resource Error");
      console.log(error);
    });
}
Enter fullscreen mode Exit fullscreen mode

Global store

$ npm install @reduxjs/toolkit
$ npm install react-redux
Enter fullscreen mode Exit fullscreen mode

How to create a store

createSlice

  1. Create a directory to keep everything, store
  2. Create a file to handle the update and reading of a specific global variable. Lets call it a slice.js
  3. Initialize the object createSlice({}) with values:
    1. name: A unique string within the global stores
    2. initialState: {}: The default, initial state of the global variable. The keys in this object will be updated in the reducers
    3. reducers: {}: Here we declare
    4. You can use switch statements when having multiple variables
// currentUserSlice.js
import { createSlice } from "@reduxjs/toolkit";

export const currentUserSlice = createSlice({
  name: "currentUser",
  initialState: {
    user: null,
  },
  reducers: {
    updateCurrentUser: (state, action) => {
      state.user = action.payload;
    },
  },
});

// Action creators are generated for each case reducer function
export const { updateCurrentUser } = currentUserSlice.actions;

export default currentUserSlice.reducer;
Enter fullscreen mode Exit fullscreen mode

Import all the store slices within the global store

import { configureStore } from "@reduxjs/toolkit";

// reducer import
import currentUserReducer from "./currentUserSlice";

const store = configureStore({
  reducer: {
    currentUser: currentUserReducer,
  },
});

export default store;
Enter fullscreen mode Exit fullscreen mode

Then, read and update persisted store value where ever

// Read
import { useDispatch, useSelector } from "react-redux";

const Component = function Component() {
  const dispatch = useDispatch();

  // Update
  dispatch(updateCurrentUser({ name: "Axel", foo: true }));

  // Read value
  const currentUser = useSelector((state) => state.currentUser.user);

  return null;
};

export default Component;
Enter fullscreen mode Exit fullscreen mode

createReducer

  1. Create a directory to keep everything, store
  2. Create actions directory to keep all defined action names for specific reducers
    1. createAction contains action name which will be used to dispatch payload
   // /actions/counterActions.js
   import { createAction } from "@reduxjs/toolkit";
   export const increment = createAction("counter/increment");
Enter fullscreen mode Exit fullscreen mode
  1. Create a reducer directory to handle the update and reading of a specific global variables. Lets call it a resourceReducer.js
  2. Create initialState: {} for variable/state
  3. import createReducer({}) and set:
    1. initialState argumenet
    2. builder: A callback object which provides addCase, addMatcher and addDefaultCase functions that may be called to define what actions this reducer will handle.
   // /reducers/counterReducer.js
   const counterReducer = createReducer(initialState, (builder) => {
     builder.addCase(increment, (state, action) => {
       state.value++;
     });
   });
Enter fullscreen mode Exit fullscreen mode

Create store

// store.js
import { configureStore } from "@reduxjs/toolkit";
import booksReducer from "./reducers/booksReducer";

const store = configureStore({
  reducer: { books: booksReducer },
});

export default store;
Enter fullscreen mode Exit fullscreen mode

Then, read and update persisted store value where ever

// Read
import { useDispatch, useSelector } from "react-redux";
import { deleteBook } from "../../store/actions/booksActions";

const Component = function Component() {
  const dispatch = useDispatch();

  // Update
  dispatch(deleteBook(id));

  // Read value
  const books = useSelector((state) => state.books.books);

  return null;
};

export default Component;
Enter fullscreen mode Exit fullscreen mode

For both ways, initialize store at top level component

// Top level component, e.g App.js
import { Provider } from "react-redux";
import store from "../store/store";

const App = function App() {
   <Provider store={store}>
      { children }
   <Provider>
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Routing

$ npm install react-router-dom
Enter fullscreen mode Exit fullscreen mode

Routes structure

<!-- At top level -->
<BrowserRouter>
  <div />
</BrowserRouter>
Enter fullscreen mode Exit fullscreen mode

then

<Routes>
  <Route path="/" element={<Dashboard />}>
    <Route path="tasks" element={<DashboardTasks />} />
  </Route>
</Routes>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)