A few years ago, realizing that both Javascript and React are probably the future of my career in web development, I slowly started reading more and casually learning what I could. I’ve come from such a front-of-the-front-end mindset, bordering on being a developer envying to be a designer, that learning Javscript has taken years for me.

Now that I have both training experience and real-world application of React, I want to jot down various things that I’ve learned as well as still struggle with. (It’ll also be entertaining to re-read this in a while to see how primitive my likes and dislikes are!)

Logical Operators, aka &&

I think this is one of my favorite ways to render components in React. It’s concise and very readable.

const [ activeElement, setActiveElement ] = useState(false);

return (
  <>
    {activeElement && <Accordion onClick={handleClick} />}
  </>
)

Is activeElement true? Sweet, let’s render that Accordion component. Easy to understand, easy to remember.

Form components

One of the more confusing parts of React is Controlled Components vs Uncontrolled Components. Most of the components I’ve written are uncontrolled because of the amount of things I have to do with them. In fact, I find it difficult to justify writing controlled components because doing this misses things for me.

<input
  className="contact-input"
  id="first-name"
  type="text"
  name="first-name"
  defaultValue={first_name}
  onClick={() => setSelectedField("first-name")}
  onKeyDown={e => handleKeyDown(e, "first-name")}
  onChange={e => setData({ ...data, first_name: e.target.value })}
  onKeyUp={validateInput}
/>

See all of these event handlers? Whether it’s validation or another key dependent event, even a custom click handler for custom action, controlled components seem too restricted in what they provide. The biggest drawback for uncontrolled components, unfortunately, is taking the power away from the form’s global handlers like onSubmit. You have to handle this event in the click handler or keydown handler to be able to send or receive the proper data for the element.

Functional Components + Hooks > Class Components

Keeping a mindset of using state in a hook, this allows a few quite appealing benefits.

  • Avoids prop drilling – Whether it’s encapsulating state with useState() or accessing it more globally with useReducer(), state doesn’t have to flow through multiple components to be manipulated as props
  • Less code – It feels and looks better to write functional components with hooks like useState().
  • What lifecycle methods? – I didn’t have to spend a lot of time with a method like ComponentDidMount (among the rest) before I started using useEffect() for most methods to work with data. The more I use it, the more I like its simplicity of helping data flow.

I much prefer updating state with useState() instead of setState(), despite doing similar things. Maybe this is just my personal optics?

Avoiding Prop Drilling

It took me some time to really get the concept of state and props, despite the seemingly simple ways to use them. One of the least favorite things I have to do is find where data starts and how it flows. When you have a microapp that declares a lot of state at top, somehow the the child components need to use a lot of that state and it could pass several levels down before it gets to the correct component for updating as state. Here’s a small example.

function Profile() {
  const [name, setName] = React.useState("")
  
  return <Form name={name} setName={setName} />
}

function Form({name, setName}) {
  const handleChange = e => {
    setName(e.target.value)
    // Do other things here...
  }

  return (
    <div class="form-component">
      <input 
        className="form-input"
        value={name} 
        onChange={() => handleChange(e)}
      />
      <button type="button" onClick={() => setName(name)}>Update
    </div>
  )
}

You get the idea even if this is imperfect. Essentially, we’re giving this form two ways to update: first through the normal onChange method which updates state, which can then be submitted normally, and second using a normal button that sets the name that was already updated by the input field. While this is fairly simple, as an app grows, such as multiple fieldsets of form fields or possibilities of what needs to be stored, updated, created, and so on, props need to be passed down to the various components that are especially written for the form.

If anything, using hooks has made my functions pretty single purposed in what they do to avoid complexity. Maybe it’s more verbose in some ways but it’s ultimately more readable.

Manipulating fetched data

JSON data is still one of my bigger challenges as I learn React and modern Javascript at broad. It can be tedious trying to figure out how to get data from an API to the component in the most efficient way.

Let’s fetch some data.

function PeopleProfiles() {
  const [ profiles, setProfiles ] = useState([])
  const [ activeProfile, setActiveProfile ] = useState(undefined)

  const fetchData = async () => {
    const results = await fetch("https://swapi.co/api/people/1/")
      .then(data => setProfiles(data))
      .catch(err => setErrors(err))
    const activePorfileExists = results.data.some(item => activeProfile === item.name)

    if (!activeProfileExists) setActiveProfile(results.data[0].name)
    setProfiles(results.data)
    return results
  }

  useEffect(() => {
    fetchData()
      .then(results => setActiveProfile(results.data[0].name))
  }, []);
}

Note: this probably won’t work but it’s an okay example for this purpose

Once the data is fetched from the API, we add the data to the profiles state using setProfiles. From there, we can replace, update, create and delete as needed. For visual purposes, there’s an active profile state that will choose the first object if no other profiles are in the active state.

All of this is performed when the component mounts inside of useEffect(). You can see that we’re only calling it once

Because we’re calling the data inside of useEffect() with an empty array as the second argument, this only runs when the component mounts the first time. Any time I tried to add state to the second argument, I kept getting a 429 error where it makes too many calls. I needed to update the state dynamically, which would be equivalent to componentDidUpdate.

I found a better way to update the view with new data is to fetch the data outside of useEffect() and call this function from the component or method that needs the view to update and show the updated data.

Let’s say, within the profile component, I have an input that allows me to update the data. In an ideal scenario, API data fetches are encapsulated into a global file. This app isn’t big enough for that so I’m passing fetchData down to the child component in order to update the view with new data.

  return (
    <>
      <form
        className="Form Form--LovedOnesSpecialDates"
        id="editLovedOne"
      >
        <div className="Form--LovedOnesSpecialDates__wrapper">
          {Profiles.map(profile =>
            <Profiles
              key={profile.id}
              fetchData={fetchData}
            />  
          )}
        </div>
      </form>
    </>
  );

I think this is one of the biggest problem areas with using React. Best practices for fetching and manipulating data have changed a few times as the language has updated itself. I’ve dived deep into React after ES6 was a big part of React via babel and webpack. I also didn’t have to spend a lot of time to understand React’s class component structure. There was just Javascript

But still, there’s a lot of legacy and historical knowledge of plain Javascript that is needed to really help understand the nuances of what React is doing whether it’s mapping through an array or knowing how to pass data from the API to the application’s state.

Conditional loading

Related to logical operators above, React’s conditional loading is not always obvious but interesting nonetheless.

const LovedOne = ({
  id, // number
  activeProfile, // string that's actual a number
  showAddProfile // boolean
}) => {
  return (
    <article
      className={`Profile${parseInt(activeProfile) === id ? " profile-active" : ""}`}
      onKeyDown={!showAddProfile ? handleProfileSwitcher : undefined}
      onClick={!showAddProfile ? handleProfileSwitcher : undefined}
    >
      // Add code here
    </article>
  )
}

It took me too long to find these patterns for render props.

For some reason, I could not pass down a number in the render prop called activeProfile. The console kept complaining so I had to turn the number into a string to get it into this component. So how do I actually use it?

The first attribute is the using a ternary function to set a specific class. The part that wasn’t obvious was matching the id to the activeProfile, which weren’t matching since it’s a string and number. I guess a using loose equality with a == might have solved it, but some linters don’t like it in some situations so I always default to strict equality ===. Either way, I had to turn the string into a number to be able to evaluate if they equal each other.

The second pattern was also a ternary that uses undefined to prevent onKeyDown or onClick from rendering in the markup. This was necessary because at larger viewport widths, these article elements don’t need to be used to help switch the active profile.

The rest

I think I’ll never stop cringing at PascalCase component names both in markup and stylesheets or using className instead of class among other things. I’m still caught in between writing classical components, HTML, CSS and JS vs how React based components. Let’s see what another year of this does!