MoveStateToChildComponent

/icons/calendar.svg

Last update

Sep 13, 2024

This codemod refactors React components by moving useState hooks from parent components to child components when the state and setter function (setState) are passed down as props. The goal is to simplify the parent components and allow child components to manage their own internal state when appropriate.

You can find the implementation of this codemod in the Studio here

Example

Case 1: Basic Prop Drilling

Before:

function Parent() {
const [count, setCount] = useState(0);
return <Child count={count} setCount={setCount} />;
}
function Child({ count, setCount }) {
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

After:

function Parent() {
return <Child />;
}
function Child() {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

Case 2: Handling Destructured Props

Before:

function Parent() {
const [rating, setRating] = useState(null);
return (
<>
<h1>Product</h1>
<ProductRating rating={rating} setRating={setRating} />
</>
);
}
function ProductRating({ rating, setRating }) {
return (
<>
<label htmlFor="rating">Rating</label>
<input
type="number"
id="rating"
onChange={(e) => setRating(parseInt(e.target.value))}
/>
{rating && <p>Rating is {rating}</p>}
</>
);
}

After:

function Parent() {
return (
<>
<h1>Product</h1>
<ProductRating />
</>
);
}
function ProductRating() {
const [rating, setRating] = useState(null);
return (
<>
<label htmlFor="rating">Rating</label>
<input
type="number"
id="rating"
onChange={(e) => setRating(parseInt(e.target.value))}
/>
{rating && <p>Rating is {rating}</p>}
</>
);
}

Case 3: Conditional Rendering

The codemod does not move useState hooks in parent components if the child component is conditionally rendered. This is to avoid breaking logic that depends on certain conditions being met for state management.

Before:

function Parent() {
const [count, setCount] = useState(0);
return (
<div>
{condition ? (
<Child count={count} setCount={setCount} />
) : (
<OtherChild />
)}
</div>
);
}
function Child({ count, setCount }) {
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

After:

function Parent() {
const [count, setCount] = useState(0);
return (
<div>
{condition ? (
<Child count={count} setCount={setCount} />
) : (
<OtherChild />
)}
</div>
);
}
function Child({ count, setCount }) {
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

Build custom codemods

Use AI-powered codemod studio and automate undifferentiated tasks for yourself, colleagues or the community

background illustrationGet Started Now