Screenshot 2023-03-19 at 5.29.17 PM.png

While reusability is good we need to maintain a balance between how much reusable code we need and how much separation of concern we need.

Few key points to keep in mind when architecting inside our current folder structure

<aside> 💡 “Everything must be made as simple as possible. But not simpler.” - Albert Einstein

</aside>

When to make components or abstract out pieces?

It is a good idea to make components when we can have god separation of concerns inside one file and abstracting the component helps increase the overall readability and simplicity

Example

Normal Data Fetching

import React from 'react';

import TextInput from './TextInput.js';
import SearchResult from './SearchResult.js';

const ENDPOINT = '/api/something';

function App() {
  const [
    searchTerm,
    setSearchTerm,
  ] = React.useState('');
  const [
    searchResults,
    setSearchResults,
  ] = React.useState(null);

  // idle | loading | success | error | empty
  const [status, setStatus] = React.useState(
    'idle'
  );

  async function handleSearch(event) {
    event.preventDefault();

    setStatus('loading');

    const url = `${ENDPOINT}?searchTerm=${searchTerm}`;
    const response = await fetch(url);
    const json = await response.json();

    if (json.ok) {
      setSearchResults(json.results);
      setStatus(
        json.results.length > 0
          ? 'success'
          : 'empty'
      );
    } else {
      setStatus('error');
    }
  }

  return (
    <>
      <header>
        <form onSubmit={handleSearch}>
          <TextInput
            required={true}
            label="Search"
            placeholder="The Fifth Season"
            value={searchTerm}
            onChange={(event) => {
              setSearchTerm(event.target.value);
            }}
          />
          <button>Go!</button>
        </form>
      </header>

      <main>
        {status === 'idle' && (
          <p>Welcome to book search!</p>
        )}
        {status === 'loading' && (
          <p>Searching...</p>
        )}
        {status === 'error' && (
          <p>Something went wrong!</p>
        )}
        {status === 'empty' && (
          <p>No results</p>
        )}
        {status === 'success' && searchResults.length > 0 ?
					(
          <div className="search-results">
            <h2>Search Results:</h2>
            {searchResults?.map((result) => (
              <SearchResult
                key={result.isbn}
                result={result}
              />
            ))
						:
						<p>No results found</p>
						}
          </div>
        )}
      </main>
    </>
  );
}

export default App;

Option 2 with valid separation of concern

import React from 'react';

import TextInput from './TextInput.js';
import SearchResult from './SearchResult.js';

const ENDPOINT =
  '/api/something';

function App() {
  const [
    searchTerm,
    setSearchTerm,
  ] = React.useState('');
  const [
    searchResults,
    setSearchResults,
  ] = React.useState(null);

  // idle | loading | success | error
  const [status, setStatus] = React.useState(
    'idle'
  );

  async function handleSearch(event) {
    event.preventDefault();

    setStatus('loading');

    const url = `${ENDPOINT}?searchTerm=${searchTerm}`;
    const response = await fetch(url);
    const json = await response.json();

    if (json.ok) {
      setSearchResults(json.results);
      setStatus('success');
    } else {
      setStatus('error');
    }
  }

  return (
    <>
      <header>
        <form onSubmit={handleSearch}>
          <TextInput
            required={true}
            label="Search"
            placeholder="The Fifth Season"
            value={searchTerm}
            onChange={(event) => {
              setSearchTerm(event.target.value);
            }}
          />
          <button>Go!</button>
        </form>
      </header>

      <main>
        {status === 'idle' && (
          <p>Welcome to book search!</p>
        )}
        {status === 'loading' && (
          <p>Searching...</p>
        )}
        {status === 'error' && (
          <p>Something went wrong!</p>
        )}
        {status === 'success' && (
          <SearchResultList
            searchResults={searchResults}
          />
        )}
      </main>
    </>
  );
}

function SearchResultList({ searchResults }) {
  if (searchResults.length === 0) {
    return <p>No results</p>;
  }

  return (
    <div className="search-results">
      <h2>Search Results:</h2>
      {searchResults?.map((result) => (
        <SearchResult
          key={result.isbn}
          result={result}
        />
      ))}
    </div>
  );
}

export default App;

For small components it may not look like the readability is getting improved here but in a larger codebase where there are multiple business logic happening inside a single file adding ternaries everywhere makes the code difficult to read over time

Now where would these type of components go?

Search here is very context specific hence components like these must belong to the specific folder either admin or startup