React BoardBuilder
Tags: react, javascript, mui
Published: 2022-06-15 18:13:35


This idea was sparked by question based forms that sort the user into a group (Find out which Harry Potter house you belong to). I had originally planned to make a site that leads you to the perfect bike for your style of riding. I quickly realized that every question would be dependent on the previous selection and formatting the data could quickly become cluttered, so I went back to the drawing board. I still liked the idea of a question form connected to a specific outcome.
The application I made is a similar idea, but applied to skateboards. This application works with you to build a complete skateboard based on what style of riding you want.

#ReadMe.md
###Features:
- Homepage display with navigation panel
- Step-by-step guide to build out your board
- List created boards
- Delete for each board

###Tech Stack: 
JavaScript React, MUI

###Component Hierarchy:
![Component Hierarchy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xv0hwtpdkxcp1urxoo08.png)

#Organizing Data & useState
Working with nested data proved a difficult task. I reformatted the db.json several times throughout this build to keep the code clean and minimal. I also very quickly learned the value of good event and variable names in order to better manage props. 

The useState hook updates React's internal state. `boards` state was kept inside of the App component in order for the children components to have access via props. State for `newBoard` was kept inside the BoardBuilder component along with the data for each `step` and MUI's `activeStep` functionality. 

#Controlled Component 
Using state to derive input value makes a controlled input. In React, rather than using a selected attribute on `<select>`, `value={state}` should be used for controllable props. 

Below you can see the complications in making `<select>` a controlled input. I wasn't able to pass the `part` variable as a value attribute because it was outside of the scope.  

![Selector component uncontrolled](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yi308z89s09h1wkyb36c.png)

I considered reformatting my db.json again, but I wanted to avoid adding a third fetch to my application. I tried to reformat to a checkbox instead, but that became an issue when I needed to restrict the selection to a single item. Eventually, I revisited the select tag with a simpler version (without using MUI). 

I created a `part` variable in state and set `value={part}`. When a part is selected, handleChangePart saves it in state, and then it is passed to the callback function handleChange. 

![Selector component controlled](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9dkdxxt09hqmv9y6phvy.png)

From there, the handleChange inside of the BoardBuilder component is responsible for building the `newBoard` object from the `parts`. Note the splice to make a copy of the previous state and the object key being targeted with the `name` value as an attribute of select.

```
const handleChange = (e) => {
    setNewBoard({...newBoard, [e.target.name] : e.target.value})
  };
```

I also set the initial state of a newBoard to the first available option so that it can't default to an empty string.

```
const [newBoard, setNewBoard] = useState({
    deck: 'standard',
    trucks: 'standard kingpin',
    wheels: 'skatepark',
    risers: 'risers',
    griptape: 'griptape'
});
```

#Restful API
I use json-server for POST and DELETE requests. Like the example below, we must get the promise back from the fetch request before setting state. I used splice to make a copy, rather than modifying the original state of `boards`.

```
  const handleAddBoard = (newBoard) => {
    fetch("http://localhost:3001/completeboards", {
      method: 'POST',
      headers: { 
        "Content-Type": "application/json", 
      },
      body: JSON.stringify(newBoard),
    })
    .then(r => r.json())
    .then((data) => setBoards([...boards, data]))
  };
```

#useEffect & Dependency Arrays
I implemented the useEffect hook twice in this application. First, to fetch boards and initially `setBoards` and again inside of the BoardBuilder component to fetch and `setStep`.
 
I had initially thought that `boards` should be the dependency array value so that when that value changes, the side effect fires. However, I realized this is not necessary because boards is saved in state and state is updated after each POST or DELETE to the boards data. If a an object is inside the dependency array, it will infinitely fetch. I used empty dependency arrays on both so that they each only run once when the component initially renders. 

```
  useEffect(() => {
    fetch("http://localhost:3001/completeboards")
    .then(r => r.json())
    .then((data) => setBoards(data))
  }, []);
```

Note that the db.json should be run with --p 3001. 

#MUI
I worked with [MUI](https://mui.com/) for a consistent styling.  The 'Stepper' component was used (as BoardBuilder) to map through the process of building a board. Within that, I needed to also map through the `parts` data inside of a Select component. I was able to clean up some of the BoardBuilder code from the original MUI formatting by adding `steps` into db.json and fetching it. 

I also used MUI's AppBar for the navigation bar and their Card component to display the results.

**Pros:** The styling is consistent and clean throughout the application. It's easy to integrate and has good documentation (depending on the version, I used v5.8.4).

**Cons:** Similarly to working with MaterializeCSS, I had issues adding my own styling along with MUI. There is a learning curve for adding images and changing MUI's "theme". It also clutters your code quite a bit. Theres a lot of extra imports and even some items added to state.

Imports for changing theme:

`import {ThemeProvider, createTheme } from '@mui/material/styles';`

#React Takeaways 

* React uses declarative code - JSX tells what to do, but not how to do it. AKA - no more document.createElement() and appending everything. 🙌
* React components allow for reusable code! 👏 I only needed one BoardBuilder and one Result component and was able to map through with the data I wanted.
* Setting state with a new object will cause a re-render with the updated info! No need to worry about complex DOM manipulation, again, less typing = efficiency. 👌

The overall key to React is understanding inverse data flow. 


Checkout my [GitHub](https://github.com/JordanTaylorJ/board-builder) repo to see the full code!