DEV Community

Pedro Uzcátegui
Pedro Uzcátegui

Posted on

React Best Practices

1. Every prop provided to a component has a default value of true.

When we pass a prop (even without a value), the mere existence of that prop, is going to return true. So if we want to render if true, we can simply write the component like this:

export default function App() {
  return (
    <main>
      <Navbar title="My Special App" />
    </main>
  );
}

function Navbar({ title }) {
  return (
    <div>
      {title} // Will not show if false
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

2. Move Unrelated Code into Separate Components

Let's say we have this:

export default function App() {
  const posts = [
    {
      id: 1,
      title: "How to Build YouTube with React"
    },
    {
      id: 2,
      title: "How to Write Your First React Hook"
    }
  ];

  return (
    <main>
      <Navbar title="My Special App" />
      <ul> // We could refactor this>>>>>>>>>
        {posts.map(post => ( 
          <li key={post.id}>
            {post.title}
          </li>
        ))}
      </ul> // <<<<<<<<<We could refactor this
    </main>
  );
}

function Navbar({ title }) {
  return (
    <div>
      <h1>{title}</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Is not clean because we can encapsulate that behavior in a separate component and make it easier to read.

The solution, is to create a new component called "FeaturedPosts" that is going to render out the posts.

export default function App() {
 return (
    <main>
      <Navbar title="My Special App" />
      <FeaturedPosts />
    </main>
  );
}

function Navbar({ title }) {
  return (
    <div>
      <h1>{title}</h1>
    </div>
  );
}

function FeaturedPosts() {
  const posts = [
    {
      id: 1,
      title: "How to Build YouTube with React"
    },
    {
      id: 2,
      title: "How to Write Your First React Hook"
    }
  ];

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

3. Components should live in their own files. Also, if a certain component is only going to live for another component, then it shouldn't have its own file.

export function ButtonPrimary({text}){ // We export what we're going to use.
  return(
    <Button class="primary">
      {text}
    </Button>
  )
}

function Button({children}){ // And we don't export what we won't
  return(
    <button>
      {children}
    </button>
  )
}
Enter fullscreen mode Exit fullscreen mode

4. Inline Styles for less bloated code

This means: Define an object called styles, and then use it into your inline styles. This will be cleaner than passing the entire object to the inline style.

export default function App() {
  const styles = {
    main: { textAlign: "center" }
  };

  return (
    <main style={styles.main}>
      <Navbar title="My Special App" />
    </main>
  );
}

function Navbar({ title }) {
  const styles = {
    div: { marginTop: "20px" },
    h1: { fontWeight: "bold" }
  };

  return (
    <div style={styles.div}>
      <h1 style={styles.h1}>{title}</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

5. If you just need to conditionally render if true, use the Logical AND operator(&&)

This operator checks if the expression on the left is truthy. If the expression is any of those, it will execute/render the part on the right. If not, it will execute the left part.

Note 1: Don't mix with the nullish coalescing operator (??) which checks for undefined or null.

Note 2: Truthy is a set of values that are converted to booleans through type coercion.

The example:

import React, { useState } from 'react'

export const ConditionalRenderingWhenTrueBad = () => {
  const [showConditionalText, setShowConditionalText] = useState(false)

  const handleClick = () =>
    setShowConditionalText(showConditionalText => !showConditionalText)

  return (
    <div>
      <button onClick={handleClick}>Toggle the text</button>
      {showConditionalText && <p>The condition must be true!</p>}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

6. Event handlers can be provided in a different way if only the event is passed.

We usually pass events as (e) => handleSomething(e). But since there is implicit binding here, we can do simply handleSomething() and it will contain the Event context.


import React, { useState } from 'react'

export const UnnecessaryAnonymousFunctionsGood = () => {
  const [inputValue, setInputValue] = useState('')

  const handleChange = e => {
    setInputValue(e.target.value)
  }

  return (
    <>
      <label htmlFor="name">Name: </label>
      <input id="name" value={inputValue} onChange={handleChange} />
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

7. When setting the state that depends from the previous state, always access to the previous state and not the state directly.

We need to write it this way, or could lead to unexpected behavior.

import React, { useState } from 'react'

export const PreviousStateGood = () => {
  const [isDisabled, setIsDisabled] = useState(false)

  const toggleButton = () => setIsDisabled(isDisabled => !isDisabled)

  const toggleButton2Times = () => {
    for (let i = 0; i < 2; i++) {
      toggleButton()
    }
  }

  return (
    <div>
      <button disabled={isDisabled}>
        I'm {isDisabled ? 'disabled' : 'enabled'}
      </button>
      <button onClick={toggleButton}>Toggle button state</button>
      <button onClick={toggleButton2Times}>Toggle button state 2 times</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Special thanks to @thawkin3 and Freecodecamp Blogs.

Top comments (0)