With useReducer
the code is not so different from the previous module:
- Store
Context
withinitialContext
inuseReducer
- Define
Event
type - Update
Context
when the user types in the input - Add function to perform async request to fetch posts
import { useReducer } from "react";
import {
initialContext,
searchRequest,
type Context,
type Post,
} from "./shared";
type Event =
| { type: "update-query"; value: string }
| { type: "update-posts"; newPosts: Post[] };
const reducer = (context: Context, event: Event): Context => {
if (event.type === "update-query") {
return { ...context, query: event.value };
} else if (event.type === "update-posts") {
return { ...context, posts: event.newPosts };
}
return context;
};
export default function UseReducer() {
const [context, dispatch] = useReducer(reducer, initialContext);
const submitSearch = async () => {
const newPosts = await searchRequest(context.query);
dispatch({ type: "update-posts", newPosts });
};
return (
<div>
<div>
<input
type="search"
value={context.query}
onChange={(e) =>
dispatch({ type: "update-query", value: e.target.value })
}
/>
<button type="button" onClick={submitSearch}>
Search
</button>
</div>
{context.posts.map((post) => (
<div key={post.id}>
<p>{post.title}</p>
<p>{post.body}</p>
</div>
))}
</div>
);
}
useReducer
alone cannot perform async requests. Therefore, the initial fetch request is implemented the exact same way as we did with useState
, by using the useEffect
hook with an empty dependency array:
export default function UseReducer() {
const [context, dispatch] = useReducer(reducer, initialContext);
const submitSearch = async () => {
const newPosts = await searchRequest(context.query);
dispatch({ type: "update-posts", newPosts });
};
useEffect(() => {
submitSearch();
}, []);
return (
<div>
<div>
<input
type="search"
value={context.query}
onChange={(e) =>
dispatch({ type: "update-query", value: e.target.value })
}
/>
<button type="button" onClick={submitSearch}>
Search
</button>
</div>
{context.posts.map((post) => (
<div key={post.id}>
<p>{post.title}</p>
<p>{post.body}</p>
</div>
))}
</div>
);
}
With both useState
and useReducer
we are required to introduce also useEffect
to perform the initial request to fetch the default list of posts.