Dennis, Kiya | 08.01.2024

React Composition: A Viable Alternative to React Context

Webentwicklung > React Composition: A Viable Alternative to React Context

Ever since React 16.8 introduced us to React hooks, many developers started leveraging React context as a trim solution to the tedious task of "prop drilling".

What is "Prop Drilling"?

React's design revolves around building UI components, which, when bundled together, form a component tree hierarchy. For a deep nested component to access data from higher up, the data must be cascaded downwards as props, the building blocks of React components. Efforts to evade prop drilling are mainly aimed at reducing redundant component re-renders. When a higher-level component modifies its data and disseminates it using props, all intervening components get triggered to re-render.

(image sourced from the React documentation)


How does React Context help?

React Context offers an excellent solution to prop drilling. It enables smooth transportation of data directly to the components that need it, bypassing intermediary children components.

Essentially, Context represents React's interpretation of dependency injection.

Sample Code Illustration:

1const ThemeContext = React.createContext();
2
3function ThemeProvider(props) {
4  const [theme, setTheme] = React.useState("dark");
5  const value = [theme, setTheme];
6  return <ThemeContext.Provider value={value} {...props} />;
7}
8
9function ThemeDisplay() {
10  const [theme] = React.useContext(ThemeContext);
11  return <div>{`The current theme is ${theme}`}</div>;
12}
13
14function Theme() {
15  const [, setTheme] = React.useContext(ThemeContext);
16  const changeTheme = () => setTheme("light");
17  return <button onClick={changeTheme}>Change theme to light</button>;
18}
19
20function App() {
21  return (
22    <div>
23      <ThemeProvider>
24        <ThemeDisplay />
25        <Theme />
26      </ThemeProvider>
27    </div>
28  );
29}
30

The Contention Surrounding Context Usage

Although the use of React Context is becoming more common, even the official React documentation advises against its overuse.

// ... rest of the code remains unchanged

Embracing React Composition

An alternative strategy worth considering is using JSX as children, leveraging the power of composition to achieve results similar to the Context API.

While this strategy doesn't directly tackle the issue of re-rendering all child components, it offers significant benefits in terms of component reuse. For example, the Dashboard Content component, which doesn't require user data, can be reused elsewhere for a different Dashboard without needing a context provider, thereby avoiding implicit dependencies.

Sample Implementation:

1export default function App() {
2  const [user, setUser] = React.useState(null);
3
4  return (
5    <div>
6      {user ? (
7        <LoggedinWrapper>
8          <Homepage>
9            <LogoutButton onLogout={() => setUser(null)} />
10            <Navigation />
11            <HomepageContent>
12              <Profile user={user} />
13            </HomepageContent>
14          </Homepage>
15        </LoggedinWrapper>
16      ) : (
17        <SigninPage onLogin={() => setUser({ name: 'Bob' })} />
18      )}
19    </div>
20  );
21}
22
23function LogoutButton({ onLogout }) {
24  return <button onClick={onLogout}>Logout</button>;
25}
26
27function LoggedinWrapper({ children }) {
28  return (
29    <React.Fragment>
30      <h1>You are signed in!</h1>
31      {children}
32    </React.Fragment>
33  );
34}
35
36function Navigation() {
37  return (
38    <React.Fragment>
39      <h2>Dashboard Nav</h2>
40    </React.Fragment>
41  );
42}
43
44function Homepage({ children }) {
45  return (
46    <React.Fragment>
47      <h3>Dashboard</h3>
48      {children}
49    </React.Fragment>
50  );
51}
52
53function HomepageContent({ children }) {
54  return (
55    <React.Fragment>
56      <h3>Homepage</h3>
57      {children}
58    </React.Fragment>
59  );
60}
61
62function Profile({ user }) {
63  return (
64    <ul>
65      <li>Username: {user.name} </li>
66    </ul>
67  );
68}
69
70function SigninPage({ onLogin }) {
71  return (
72    <React.Fragment>
73      <h1>Sign In</h1>
74      <button onClick={onLogin}>Login</button>
75    </React.Fragment>
76  );
77}
78

In contrast, the mandatory need for a context provider can be challenging when trying to render a component outside its allotted provider. Often, developers encapsulate the entire application within a global context provider, which could lead to performance issues, as previously mentioned.

In a nutshell, composition can serve as a feasible alternative to relying on React context to prevent prop drilling.

References

Inhalt
  • What is Prop Drilling in React?
  • How Does React Context Help?
  • What Are the Concerns Surrounding Context Usage?
  • How Can React Composition Help?
Dennis Hundertmark
Dennis (Softwareentwickler)

Als Frontend-Experte und Angular-Enthusiast gestalte ich Webanwendungen, die Technik und Design gekonnt zusammenführen. Meine Stärke liegt in der Entwicklung benutzerzentrierter Lösungen, die sowohl f... mehr anzeigen

Gitlab
Kiya

... ist unsere engagierte und leidenschaftliche Künstliche Intelligenz und Expertin für Softwareentwicklung. Mit einem unermüdlichen Interesse für technologische Innovationen bringt sie Enthusiasmus u... mehr anzeigen

More about this topic

More from Dennis

Unsere Entwicklungsexpertise

Standort Hannover

newcubator GmbH
Bödekerstraße 22
30161 Hannover

Standort Dortmund

newcubator GmbH
Westenhellweg 85-89
44137 Dortmund