# 6. Principios SOLID

{% file src="<https://2587136002-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqvBskYj09PBRfB5OZV01%2Fuploads%2FnQNc5XVfXVcp8BbYYQIl%2FPrinciples_and_Patterns.pdf?alt=media&token=7bcf784e-4dbc-4680-adaf-3f8ba01ffd48>" %}
*Martin, Robert C. (2000).* [*"Design Principles and Design Patterns"*](https://web.archive.org/web/20150906155800/http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf)
{% endfile %}

### Single Responsibility Principle

Every element should do exactly one thing

{% hint style="success" %}
React: **Presentation** & **Container** components
{% endhint %}

{% tabs %}
{% tab title="Initial code" %}

```jsx
function Users() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users", { method: "GET" })
      .then((response) => response.json())
      .then(setUsers);
  }, []);

  return (
    <section>
      <h1>Users: </h1>
      <ul>
        {users.map((user) => (
          <li>{user.username}</li>
        ))}
      </ul>
    </section>
  );
}
```

{% endtab %}

{% tab title="=> Presentation component" %}

```jsx
function Users({ users }) {
  return (
    <section>
      <h1>Users: </h1>
      <ul>
        {users.map((user) => (
          <li key={`user-${user.username}`}>{user.username}</li>
        ))}
      </ul>
    </section>
  );
}
```

{% endtab %}

{% tab title="=> Container component" %}

```jsx
function UsersContainer() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users", { method: "GET" })
      .then((response) => response.json())
      .then(setUsers);
  }, []);

  return <Users users={users} />;
}
```

{% endtab %}
{% endtabs %}

### Open/Close Principle

You should be able to add functionality to some module, without modifying its existing source code

{% hint style="info" %}
Composición >>> Herencia
{% endhint %}

{% hint style="success" %}
React: división en **componentes**&#x20;
{% endhint %}

{% tabs %}
{% tab title="Container component" %}

```jsx
function UsersContainer() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users", { method: "GET" })
      .then((response) => response.json())
      .then(setUsers);
  }, []);

  return <Users users={users} />;
}
```

{% endtab %}

{% tab title="=> composition component" %}

```jsx
function Users({ users }) {
  return (
    <section>
      <h1>Users: </h1>
      <ul>
        {users.map((user) => (
          <User user={user} />
        ))}
      </ul>
    </section>
  );
}

function User({ user }) {
  return (
   <article key={`user-${user.username}`} className="user">
      <span>{user.username}</span>
      <div className="user__contact-info">
        {user.company.name}
        {user.email}
      </div>
    </article>
  );
}
```

{% endtab %}
{% endtabs %}

### Substitution Principle (Liskov)

{% hint style="info" %}
Cualquier objeto se tiene que poder sustituir por un objeto que sea un subconjunto
{% endhint %}

{% hint style="success" %}
React: Las propiedades de los components representan su API
{% endhint %}

```diff
function Users({ users }) {
  return (
    <section>
      <h1>Users: </h1>
      <ul>
        {users.map((user) => (
-          <User user={user} />
+          <UserCard user={user} />
        ))}
      </ul>
    </section>
  );
}
```

### Interface Segregation Principle

{% hint style="info" %}
No fuerces cumplir interfaces que no se usen.
{% endhint %}

{% hint style="success" %}
React: Lista solo las propiedades necesarias (no dependas de propiedades que no necesitas)
{% endhint %}

```diff
-function UserCard({ user }) {
+function UserCard({ username, company, email }) {
```

### Dependency Inversion Principle <a href="#dependency-inversion-principle-dip" id="dependency-inversion-principle-dip"></a>

{% hint style="info" %}
Interacciona con los detalles usando abstracciones
{% endhint %}

{% hint style="success" %}
React: Extracción a custom hooks
{% endhint %}

{% tabs %}
{% tab title="custom hook" %}

```jsx
function useUsers() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    let isSubscribed = true;

    api.fetchUsers().then((users) => {
      if (isSubscribed) {
        setUsers(users);
      }
    });

    const cleanUp = () => {
      isSubscribed = false;
    };
    return cleanUp;
  }, []);

  return { users };
}

function UsersContainer() {
  const { users } = useUsers();

  return <Users users={users} />;
}
```

{% endtab %}

{% tab title="container component: no entra en el detalle" %}

```jsx
function UsersContainer() {
  const { users } = useUsers();

  return <Users users={users} />;
}
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://manu-artero-anguita.gitbook.io/buenas-practicas-con-react/sesion-3/6.-principios-solid.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
