In React, it's very common to share properties between components and their descendents. It can become a hassle to have to add these properties for each of these components: a problem commonly known as "prop drilling." See below for an example (copied from here):
import { useState } from 'react';
function App() {
const [user, setUser] = useState({ name: 'Steve' });
return (
<div>
<Navbar />
<MainPage user={user} />
</div>
);
}
export default App;
// Navbar Component
function Navbar() {
return <nav>Demo App</nav>;
}
// MainPage Component
function MainPage({ user }) {
return (
<div>
<h3>Main Page</h3>
<Content user={user} />
</div>
);
}
// Content Component
function Content({ user }) {
return (
<div>
<Message user={user} />
</div>
);
}
// Message Component
function Message({ user }) {
return <p>Welcome {user.name}</p>;
}
Prop drilling was often solved by using Redux, but a lot of developers are now arguing that React Context (along with useReducer
) now replaces the need for Redux to solve prop drilling. Developers have also argued the opposite, and that using React Context triggers unnecessary renders, which can cause major performance issues.
Real Example
I created a base example to better understand the Redux store, and how it differs from React Context. The example is adapted from Kent C. Dodds' example on performance optimization via colocation. In each of the examples, try changing the "Dog Name." You will notice that the examples marked as "slow" will lag.
Explanation
This is because these implementations are forcing a rerender of portions of the code that are unrelated to the dog
state variable (for more details, I suggest studying the original post). Kent suggests fixing this problem by moving the dog
variable down to the child component where it's actually used (a.k.a. colocation), but we are more focused on doing an apples to apples comparison of Redux and React Context.
Pay close attention to "Redux - Single Store" (WithRedux.tsx
) and "React Context (slow)" (WithReactContext.tsx
). They're written to be as similar as possible. The only difference between them is Redux and React Context, but the React Context version is significantly slower!
At the time of writing, it does not seem like React Context will change their implementation any time soon.
Does React Context replace Redux?
So it looks like the answer to our question is a resounding "no," at least not by itself. In order to fully reproduce the functionality of Redux, we will not only need React Context and useReducer
, but we will also need to wrap the affected code with memo
, useMemo
, or in some cases, useEffect
.
In the end, that's a lot of work to implement something that Redux can do out of the box. It's up to you to determine if that's the kind of tradeoff you want.
While this may seem like a big letdown, I'd also like to point out that Redux has changed a lot over the years, especially with the inclusion of Redux Toolkit. If you haven't looked at the docs since 2020, I highly suggest going through the newest tutorial and style guide.