В моем приложении реакции у меня есть пользовательский хук useDataObject()
, который вычисляет объект на основе значения другого хука, например useScreenWidth()
. Моя проблема в том, что я не могу разместить логики вычислений c, поэтому объект сразу готов к первому возврату:
function useScreenWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return width;
}
function useDataObject() {
const width = useScreenWidth();
const [dataObject, setDataObject] = useState();
useEffect(() => {
// Some logic that creates dataObject from width
const dataObject = {
firstValue: 2 * width,
secondValue: width + 10
};
setDataObject(dataObject);
}, [width]);
return dataObject;
}
export default function App() {
const dataObject = useDataObject();
// Can I get rid of this check?
// Currently needed to prevent "Can not read property firstValue of undefined
if (!dataObject) {
return null;
}
return (
<>
<div>Data object first value: {dataObject.firstValue}</div>
<div>Data object second value: {dataObject.secondValue}</div>
</>
);
}
См. Песочница
Поскольку useDataObject
не имеет начального состояния, мне нужно дождаться, пока первый useEffect
завершит sh, пока я не получу действительный dataObject
. Это означает, что мне нужно всегда включать нулевую проверку после вызовов useDataObject()
.
. Каков наилучший подход к выполнению логики вычислений c в useDataObject()
перед первым возвратом, а затем каждый раз, когда изменения ширины?
Один из подходов, которые я попробовал, заключался в создании внутренней функции, выполняющей вычисления:
function useDataObject() {
const width = useScreenWidth();
const [dataObject, setDataObject] = useState(calculateDataObject());
function calculateDataObject() {
// Some logic that creates dataObject from width
const dataObject = {
firstValue: 2 * width,
secondValue: width + 10
};
return dataObject;
}
useEffect(() => {
setDataObject(calculateDataObject());
}, [width, calculateDataObject]);
return dataObject;
}
Но это выглядит довольно неуклюже и сбивает с толку. Это также дает мне ошибку в сообщении, что я должен использовать useCallback()
. Разве нет более прямого пути? Спасибо!