Heim > Web-Frontend > js-Tutorial > Reagieren: Wiederverwendbar, entkoppelt und isoliert

Reagieren: Wiederverwendbar, entkoppelt und isoliert

WBOY
Freigeben: 2024-08-19 17:15:03
Original
1115 Leute haben es durchsucht

Wenn Sie an einer neuen Seite arbeiten, beginnen Sie nicht einfach damit, Komponenten auf der Seite selbst zu schreiben. Beginnen Sie mit der Individualisierung von Komponenteneinheiten, damit jede unabhängig genug ist und Änderungen am globalen Status kein erneutes Rendern verursachen. Stellen Sie sich zum Beispiel vor, Sie hätten die Aufgabe, diese Seite zu erstellen.

React: Reusable, Decoupled, and Isolated

Sie könnten wie ich, als ich das Programmieren lernte, versucht sein, alle diese Komponenten in eine einzige Datei zu schreiben.

// WRONG
export const LoginPage = () => {
  const [userId, setUserId] = useState('')
  const [password, setPassword] = useState('')

  return (
    <div>
      <div className="d-flex flex-row">
        <div id="marketing-container">
          <svg {...fbLogo} />
          <h2>Connect with friends and the world around you on Facebook</h2>
        </div>
        <div id="login-form">
          <div>
            <input id="user-id" value={userId} onChange={(e) => setUserId(e.target.value)} />
            <input id="password" value={password} onChange={(e) => setPassword(e.target.value)} />
            <button>Log in</button>
            <a href="/forgot-password">Forgot password</a>
            <br />
            <button>Create new account</button>
          </div>
          <div>
            <strong>Create a page</strong>
            <span>for a celebrity, brand or business.</span>
          </div>
        </div>
      </div>
    </div>
  )
}

export default LoginPage
Nach dem Login kopieren

Aber die Realität ist, dass viele dieser Elemente in Zukunft in der gesamten App wiederverwendet werden könnten und das bedeutet, dass sie neu geschrieben oder kopiert/eingefügt werden müssten. Wenn Sie mit einem klar definierten Design arbeiten, ist es wahrscheinlich, dass Elemente wie Legos verwendet werden. Das auf der Anmeldeseite angezeigte Logo ist dasselbe wie das auf dem Dashboard-Bildschirm, vielleicht hat es natürlich nur eine andere Größe. Das Gleiche gilt für die Benutzer-ID-Eingabe. Vom Design her wäre sie wahrscheinlich dieselbe wie die auf der Benutzerbearbeitungsseite.

Was mich zu meinem nächsten Punkt bringt: Komponenten sollten von der Geschäftslogik zur Präsentationslogik entkoppelt werden. Damit meine ich, dass der Teil, der mit dem Staat kommuniziert, eine eigene Komponente sein sollte und diese Komponente lediglich Präsentations-Requisiten an die Präsentationskomponente weitergibt.

// Presentational component
const UserIdInputComponent = ({ value, onChange }) =>
  <input value={value} onChange={onChange} />

// Logic component
export const UserIdInput = () => {
  const [value, setValue] = useState('')

  const handleChange = (e) => setValue(e.target.value)

  return <UserIdInputComponent value={value} onChange={handleChange} />
}
Nach dem Login kopieren

Dadurch können Tools wie das Storybook ordnungsgemäß funktionieren, indem nur Präsentationskomponenten exportiert werden, die von der Statusverwaltung entkoppelt sind. Es kann lästig sein, eine logiklastige Komponente in Storybook integrieren zu müssen, die API-Aufrufe durchführt und globale Zustandsänderungen vornimmt. Mit diesem Ansatz können Sie sehen, wie sich eine Komponente anhand verschiedener Requisiten optisch verändert.

Zurück zur Hauptseite. Sie können wahrscheinlich sehen, wohin ich damit will. Anstatt alles auf die gleiche Seite zu schreiben. Überlegen Sie, wie diese Komponente wiederverwendet werden kann, wie sie vom Zustand entkoppelt werden kann und wie sie isoliert werden kann, sodass sie nie wieder gerendert wird, es sei denn, die mit dieser Komponente verbundenen Requisiten ändern sich.

export const LoginPage = () => (
  <div>
    <div className="d-flex flex-row">
      <FbMarketing />
      <LoginForm />
    </div>
  </div>
)

export default LoginPage
Nach dem Login kopieren

Im besten Fall beginnen Sie so mit dem Codieren. Es wäre umständlicher, es noch einmal zu überarbeiten, sobald Sie sehen, dass alles wie erwartet funktioniert. Ich möchte schnell etwas auf dem Bildschirm sehen, die Angst beruhigen und von Anfang an mit dem Aufbau der richtigen Struktur beginnen.

const FbLogo = () => (
  <svg {...fbLogoAttributes} />
)

const FbSlogan = () => (
  <h2>Connect with friends and the world around you on Facebook.</h2>
)

const FbMarketing = () => (
  <>
    <FbLogo />
    <FbSlogan />
  </>
)
Nach dem Login kopieren

Hier finden Sie zum jetzigen Zeitpunkt alle Präsentationen. Diese können weiter individualisiert werden als FbLogoSmall, FbLogoMedium usw.

Jetzt kommt der Teil, der etwas Logik enthält, das Anmeldeformular. Ich bin mir nicht sicher, ob es „Anmelden“, „Anmelden“ oder „Anmelden“ heißt, aber wir werden weiterhin die Facebook-Terminologie „Anmelden“ verwenden.

Zur Erinnerung: Jede Komponente sollte wiederverwendbar, entkoppelt und isoliert sein.

Wiederverwendbar:

Machen wir zunächst den UserIdInput wiederverwendbar und kopieren Sie diesen Ansatz dann auf die andere Passworteingabe: Es ist erwähnenswert, dass Eingaben auf Produktionsebene andere Attribute wie Test-ID, Klassen, die sich basierend auf Requisiten ändern, Aria-Attribute, Autofokus usw. enthalten Weitere andere Requisiten/Attribute, abhängig von den Tools, die die Codebasis verwendet. Wenn Ihnen jemand sagt, dass es komplexer ist als das, was ich hier schreibe, hören Sie dieser Person zu.

// UserIdInput.js
import { useContext, createContext } from "react";

export const UserIdContext = createContext();

const UserIdInput = () => {
  const { userId, setUserId } = useContext(UserIdContext);

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

  return <UserIdInputComponent value={userId} onChange={handleChange} />;
};
Nach dem Login kopieren

Jetzt kann diese Eingabe beispielsweise im Benutzerbearbeitungsformular wiederverwendet werden. So würde die Passworteingabe aussehen:

// PasswordInput.js
import { useContext, createContext } from "react";

export const PasswordContext = createContext();

const PasswordInput = () => {
  const { password, setPassword } = useContext(PasswordContext);

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

  return (
    <div>
      <PasswordInputComponent value={password} onChange={handleChange} />
    </div>
  );
};
Nach dem Login kopieren

Entkoppelt:

Entkoppelt im Sinne der Entkopplung der Logik vom Präsentationsteil, „Geschäftslogik“ vs. visuell: Hier können wir sehen, dass Requisiten ohne Änderungen oder neue Funktionsdefinitionen in der Mitte übergeben werden, zum Teufel gebe ich sogar die jsx zurück direkt nach oben ohne Return-Schlüsselwort. Nochmals: Wenn Ihnen jemand sagt, dass es komplizierter ist, dann ist es … Beschriftungen sollten ihre eigenen Komponenten sein, Eingaben auch.

// UserIdInputComponent.js
const UserIdInputComponent = ({ value, onChange }) => (
  <div>
    <label>User Id:</label>
    <input type="text" value={value} onChange={onChange} required />
  </div>
);
Nach dem Login kopieren
// PasswordInputComponent.js
const PasswordInputComponent = ({ value, onChange }) => (
  <div>
    <label>Password:</label>
    <input type="password" value={value} onChange={onChange} required />
  </div>
);
Nach dem Login kopieren

Isoliert:

Wir haben uns bereits um den isolierten Teil gekümmert, indem wir einen Kontext erstellt haben. Wenn wir nun eine der Eingaben ändern, wird die andere Eingabe nicht erneut gerendert. Die einzigen Elemente, die neu gerendert werden, sind die geänderte Eingabe und die Schaltfläche „Anmelden“. Dies ist ein guter Indikator dafür, ob Ihre React-App richtig optimiert ist. Eine vorzeitige Optimierung ist manchmal gut. Stärkt das Team weiter.

const LoginButton = () => {
  const { userId } = useContext(UserIdContext);
  const { password } = useContext(PasswordContext);

  const onClick = (e) => {
    e.preventDefault();
    console.log("form submit", userId, password)
  };

  return <button onClick={onClick}>Log in</button>;
};
Nach dem Login kopieren

Außer! Das ist eigentlich nicht passiert, ich habe versucht, die Änderungen mithilfe des Kontexts zu isolieren, aber als es darum ging, Benutzer-ID und Passwort zu teilen, musste ich Redux verwenden, denn sobald ich UserIdProvider zum Umschließen des LoginButtons verwendet habe, wurde ein neuer Status mit neuer Benutzer-ID und neuem Passwort erstellt . So sieht es mit Redux aus.

// LoginButton.js
import { useSelector } from "react-redux";

const LoginButton = () => {
  const { userId, password } = useSelector(state => state)

  const onClick = (e) => {
    e.preventDefault();
    console.log("form submit", userId, password);
  };

  return <button onClick={onClick}>Log in</button>;
};

export default LoginButton
Nach dem Login kopieren

Hätte es wahrscheinlich schon einmal tippen sollen, aber hier ist der Redux-Store.

// store.js
import { createSlice, configureStore } from '@reduxjs/toolkit'

const login = createSlice({
  name: 'login',
  initialState: {
    userId: '',
    password: '',
  },
  reducers: {
    userId: (state, action) => {
      state.userId = action.payload
    },
    password: (state, action) => {
      state.password = action.payload
    }
  }
})

export const { userId: setUserId, password: setPassword } = login.actions

export const store = configureStore({
  reducer: login.reducer
})
Nach dem Login kopieren

Ich kenne mich mit Redux aus, aber es funktioniert einfach wunderbar, Änderungen zu isolieren, sodass ein erneutes Rendern minimiert wird. Normalerweise würde ich niemandem trauen, der Re-Renderings um jeden Preis vermeidet, aber das ist nur ein guter Hinweis auf guten Reaktionscode.

React: Reusable, Decoupled, and Isolated

Here are the updated files for the two inputs. Not a lot changed but pay attention to how easy it was for me to change only the business logic component. Changed the value selector, the handleChange function and that was it. This is one of the advantages of decoupling, it’s not that obvious with such a small component but a codebase that uses complex logic I can see how this approach can be beneficial.

// UserIdInput.js (revised final)
import { setUserId } from "./store";
import { useDispatch, useSelector } from "react-redux";

const UserIdInputComponent = ({ value, onChange }) => (
  <div>
    <label>User Id:</label>
    <input type="text" value={value} onChange={onChange} required />
  </div>
);

const UserIdInput = () => {
  const userId = useSelector(({ userId }) => userId)
  const dispatch = useDispatch()

  const handleChange = (e) => {
    dispatch(setUserId(e.target.value))
  };

  return <UserIdInputComponent value={userId} onChange={handleChange} />;
};
Nach dem Login kopieren
// PasswordInput.js (revised final)
import { useDispatch, useSelector } from "react-redux";
import { setPassword } from "./store";

const PasswordInputComponent = ({ value, onChange }) => (
  <>
    <label>Password:</label>
    <input type="password" value={value} onChange={onChange} required />
  </>
);

const PasswordInput = () => {
  const password = useSelector(({ password }) => password)
  const dispatch = useDispatch()

  const handleChange = e => {
    dispatch(setPassword(e.target.value))
  };

  return <PasswordInputComponent value={password} onChange={handleChange} />
};
Nach dem Login kopieren

The result should only highlight updates on the changed input and the login button itself like so:

React: Reusable, Decoupled, and Isolated

There’s a problem though, the labels are also updating. Let’s fix that really quick just to prove the point of over, but potentially necessary optimization. Up to your discretion.

// UserIdInput.js
import { setUserId } from "./store";
import { useDispatch, useSelector } from "react-redux";

const UserIdInputComponent = ({ value, onChange }) => (
  <input type="text" value={value} onChange={onChange} required />
);

const UserIdInput = () => {
  const userId = useSelector(({ userId }) => userId)
  const dispatch = useDispatch()

  const handleChange = (e) => {
    dispatch(setUserId(e.target.value))
  };

  return <UserIdInputComponent value={userId} onChange={handleChange} />;
};

// separated the label from the logic heavy component
export const UserIdInputWithLabel = () => (
  <div>
    <label>User id: </label>
    <UserIdInput />
  </div>
)

export default UserIdInputWithLabel
Nach dem Login kopieren

Here is the password input.

// PasswordInput.js
import { useDispatch, useSelector } from "react-redux";
import { setPassword } from "./store";

const PasswordInputComponent = ({ value, onChange }) => (
  <input type="password" value={value} onChange={onChange} required />
);

const PasswordInput = () => {
  const password = useSelector(({ password }) => password)
  const dispatch = useDispatch()

  const handleChange = e => {
    dispatch(setPassword(e.target.value))
  };

  return <PasswordInputComponent value={password} onChange={handleChange} />
};

// separated label from logic heavy component
const PasswordInputWithLabel = () => (
  <div>
    <label>Password: </label>
    <PasswordInput />
  </div>
)

export default PasswordInputWithLabel
Nach dem Login kopieren

This approach yields the following results:

React: Reusable, Decoupled, and Isolated

Fully optimized.

Available here: https://github.com/redpanda-bit/reusable-decoupled-isolated

Conclusion

There you have it, reusable, decoupled, and isolated react components. Very small example but hope that it gives you an idea of how production grade react applications look like. It may be disappointing for some to see all the work that goes into creating a good react component, but I’ll tell ya, once you are faced with a huge form that has complex elements and possibly some animation you will see positive gains on speed. The last thing you want is an input lagging behind in front of a 100 words per minute types.

References:

https://nextjs.org/

https://redux.js.org/

Das obige ist der detaillierte Inhalt vonReagieren: Wiederverwendbar, entkoppelt und isoliert. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage