Để tái tạo this.setState
hành vi hợp nhất từ các thành phần giai cấp, Phản ứng tài liệu đề nghị sử dụng các hình thức chức năng của useState
với đối tượng lây lan - Không cần cho useReducer
:
setState(prevState => {
return {...prevState, loading, data};
});
Hai trạng thái hiện được hợp nhất thành một, điều này sẽ giúp bạn tiết kiệm một chu kỳ kết xuất.
Có một lợi thế khác với một đối tượng trạng thái: loading
và data
là các trạng thái phụ thuộc . Các thay đổi trạng thái không hợp lệ trở nên rõ ràng hơn, khi trạng thái được kết hợp với nhau:
setState({ loading: true, data });
Bạn thậm chí tốt hơn có thể đảm bảo các quốc gia phù hợp bằng 1.) làm cho tình trạng - loading
, success
, error
, vv - rõ ràng trong tiểu bang và 2. bạn) sử dụng useReducer
logic trạng thái gói gọn trong một giảm:
const useData = () => {
const [state, dispatch] = useReducer(reducer, );
useEffect(() => {
api.get('/people').then(test => {
if (test.ok) dispatch(["success", test.data.results]);
});
}, []);
};
const reducer = (state, [status, payload]) => {
if (status === "success") return { ...state, data: payload, status };
else if (status === "loading") return { ...state, data: undefined, status };
return state;
};
const App = () => {
const { data, status } = useData();
return status === "loading" ? <div> Loading... </div> : (
)
}
const useData = () => {
const [state, dispatch] = useReducer(reducer, {
data: undefined,
status: "loading"
});
useEffect(() => {
fetchData_fakeApi().then(test => {
if (test.ok) dispatch(["success", test.data.results]);
});
}, []);
return state;
};
const reducer = (state, [status, payload]) => {
if (status === "success") return { ...state, data: payload, status };
else if (status === "loading") return { ...state, data: undefined, status };
else return state;
};
const App = () => {
const { data, status } = useData();
const count = useRenderCount();
const countStr = `Re-rendered ${count.current} times`;
return status === "loading" ? (
<div> Loading (3 sec)... {countStr} </div>
) : (
<div>
Finished. Data: {JSON.stringify(data)}, {countStr}
</div>
);
}
const useRenderCount = () => {
const renderCount = useRef(0);
useEffect(() => {
renderCount.current += 1;
});
return renderCount;
};
const fetchData_fakeApi = () =>
new Promise(resolve =>
setTimeout(() => resolve({ ok: true, data: { results: [1, 2, 3] } }), 3000)
);
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<div id="root"></div>
<script>var { useReducer, useEffect, useState, useRef } = React</script>
Tái bút: Đảm bảo đặt tiền tố Hooks tùy chỉnh bằng use
( useData
thay vì getData
). Gọi lại cũng được chuyển đến useEffect
không thể được async
.
useReducer