一般来说,这里的关键是将page 状态向上移动到父组件,并在您更改过滤器时将页面更改为 0。您可以使用useState 或useReducer 进行操作。
它与useState 一起工作的原因(即只有一个重新渲染)是因为 React 在事件处理程序中批量状态更改,如果没有,您仍然会得到两个 API 调用。 CodeSandbox
const PaginationComponent = ({ page, minPrice, maxPrice, setPage }) => {
const [items, setItems] = useState([]);
useEffect(() => {
get(page, minPrice, maxPrice).then(response => setItems(response));
}, [page, minPrice, maxPrice]);
return (
<div>
{items.map(item => (
<div key={item.id}>
{item.id}, {item.name}, ${item.price}
</div>
))}
<div>Page: {page}</div>
<button onClick={() => setPage(v => v - 1)}>back</button>
<button onClick={() => setPage(v => v + 1)}>next</button>
</div>
);
};
const App = () => {
const [page, setPage] = useState(0);
const [minPrice, setMinPrice] = useState(25);
const [maxPrice, setMaxPrice] = useState(50);
return (
<div>
<div>
<label>Min price:</label>
<input
value={minPrice}
onChange={event => {
const { value } = event.target;
setMinPrice(parseInt(value, 10));
setPage(0);
}}
/>
</div>
<div>
<label>Max price:</label>
<input
value={maxPrice}
onChange={event => {
const { value } = event.target;
setMaxPrice(parseInt(value, 10));
setPage(0);
}}
/>
</div>
<PaginationComponent minPrice={minPrice} maxPrice={maxPrice} page={page} setPage={setPage} />
</div>
);
};
export default App;
另一种解决方案是使用useReducer,它更透明,但也像通常使用reducer 一样,样板文件有点重。这个例子的行为有点不同,因为有一个“设置过滤器”按钮可以更改传递给分页组件的状态,更像是“现实生活”场景 IMO。 CodeSandbox
const PaginationComponent = ({ tableConfig, setPage }) => {
const [items, setItems] = useState([]);
useEffect(() => {
const { page, minPrice, maxPrice } = tableConfig;
get(page, minPrice, maxPrice).then(response => setItems(response));
}, [tableConfig]);
return (
<div>
{items.map(item => (
<div key={item.id}>
{item.id}, {item.name}, ${item.price}
</div>
))}
<div>Page: {tableConfig.page}</div>
<button onClick={() => setPage(v => v - 1)}>back</button>
<button onClick={() => setPage(v => v + 1)}>next</button>
</div>
);
};
const tableStateReducer = (state, action) => {
if (action.type === "setPage") {
return { ...state, page: action.page };
}
if (action.type === "setFilters") {
return { page: 0, minPrice: action.minPrice, maxPrice: action.maxPrice };
}
return state;
};
const App = () => {
const [tableState, dispatch] = useReducer(tableStateReducer, {
page: 0,
minPrice: 25,
maxPrice: 50
});
const [minPrice, setMinPrice] = useState(25);
const [maxPrice, setMaxPrice] = useState(50);
const setPage = useCallback(
page => {
if (typeof page === "function") {
dispatch({ type: "setPage", page: page(tableState.page) });
} else {
dispatch({ type: "setPage", page });
}
},
[tableState]
);
return (
<div>
<div>
<label>Min price:</label>
<input
value={minPrice}
onChange={event => {
const { value } = event.target;
setMinPrice(parseInt(value, 10));
}}
/>
</div>
<div>
<label>Max price:</label>
<input
value={maxPrice}
onChange={event => {
const { value } = event.target;
setMaxPrice(parseInt(value, 10));
}}
/>
</div>
<button
onClick={() => {
dispatch({ type: "setFilters", minPrice, maxPrice });
}}
>
Set filters
</button>
<PaginationComponent tableConfig={tableState} setPage={setPage} />
</div>
);
};
export default App;