我可以在 React 中使用 useEffect 来更新页面显示吗?
Can I use useEffect in React to update page display?
我正在尝试使用 useEffect 在某个状态或道具更新时更新 DOM。当我希望 DOM 更新触发时,控制台会记录我的测试,但 DOM 更新或渲染从未发生
我试图找出方法来制作一个条件语句来检查我希望 useEffect 触发的 prop 或状态是否已更改,但由于函数是 运行 我的控制台日志,但不是我的渲染,一定是我遗漏了什么。
import React, { useEffect } from 'react';
function Report( { weatherData, units }) {
let windUnits = 'mph';
useEffect(() => {
units == 'imperial' ? windUnits = 'mph' : windUnits = 'km/h';
console.log('units updated');
}, [ weatherData ]);
return (
<p id="wind">{ `${ weatherData.wind.speed }${ windUnits } ${ getWindDirection(weatherData.wind.deg) }`}</p>
)
}
export default Report;
单位来自父组件,可以通过两个按钮更改以接收不同的测量数据。 weatherData 是从 api 接收到的数据,当 api 被调用并且数据发生变化时,windUnits 应该根据指定的单位类型发生变化。
目前,虽然 console.log 有效并且正确的单位类型从父组件打印到控制台,但屏幕上的文本不会更改以匹配它。
由于只要 props (weatherData
, units
) 发生变化,组件就会重新渲染,因此您不需要使用效果。只需将正确的单位分配给 windUnits
:
const { useState } = React;
const getWindDirection = x => x;
const Report = ({ weatherData, units }) => {
const windUnits = units == 'imperial' ? 'mph' : 'km/h';
return (
<p id="wind">{ `${ weatherData.wind.speed }${ windUnits } ${ getWindDirection(weatherData.wind.deg) }`}</p>
);
};
const Demo = () => {
const [units, setUnits] = useState('imperial');
return (
<div>
<button onClick={() => setUnits('imperial')}>imperial</button>
<button onClick={() => setUnits('metric')}>metric</button>
<Report weatherData={{ wind: { speed: 10, deg: 45 }}} units={units} />
</div>
)
};
ReactDOM.render(
<Demo />,
demo
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="demo"></div>
如果您只想在 windData
更改时重新渲染组件,您可以使用 useEffect
和 useState
。 useEffect
处理副作用,不重新渲染组件,对变量的更改将在下一次渲染时丢失。 useState
另一方面将重新渲染组件。
const { useState, useEffect } = React;
const getWindDirection = x => x;
const Report = ({ weatherData, units }) => {
const [windUnits, setWindUnits] = useState('mph');
useEffect(() => {
setWindUnits(units == 'imperial' ? 'mph' : 'km/h');
}, [weatherData]);
return (
<p id="wind">{ `${ weatherData.wind.speed }${ windUnits } ${ getWindDirection(weatherData.wind.deg) }`}</p>
);
};
const windData = { wind: { speed: 10, deg: 45 }};
const Demo = () => {
const [units, setUnits] = useState('imperial');
const [data, setData] = useState(windData);
const changeSpeed = () => setData({ ...data, wind: { ...data.wind, speed: Math.random() * 100 }});
return (
<div>
<button onClick={() => setUnits('imperial')}>imperial</button>
<button onClick={() => setUnits('metric')}>metric</button>
<button onClick={changeSpeed}>Change speed</button>
<Report weatherData={data} units={units} />
</div>
)
};
ReactDOM.render(
<Demo />,
demo
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="demo"></div>
另一种选择是将 React.memo 与 areEqual
回调一起使用,并且只检查 weatherData
是否相等:
const { useState, memo } = React;
const getWindDirection = x => x;
const Report = memo(({ weatherData, units }) => {
const windUnits = units == 'imperial' ? 'mph' : 'km/h';
return (
<p id="wind">{ `${ weatherData.wind.speed }${ windUnits } ${ getWindDirection(weatherData.wind.deg) }`}</p>
);
}, ({ weatherData: prev }, { weatherData: current }) => prev === current);
const windData = { wind: { speed: 10, deg: 45 }};
const Demo = () => {
const [units, setUnits] = useState('imperial');
const [data, setData] = useState(windData);
const changeSpeed = () => setData({ ...data, wind: { ...data.wind, speed: Math.random() * 100 }});
return (
<div>
<button onClick={() => setUnits('imperial')}>imperial</button>
<button onClick={() => setUnits('metric')}>metric</button>
<button onClick={changeSpeed}>Change speed</button>
<Report weatherData={data} units={units} />
</div>
)
};
ReactDOM.render(
<Demo />,
demo
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="demo"></div>
我正在尝试使用 useEffect 在某个状态或道具更新时更新 DOM。当我希望 DOM 更新触发时,控制台会记录我的测试,但 DOM 更新或渲染从未发生
我试图找出方法来制作一个条件语句来检查我希望 useEffect 触发的 prop 或状态是否已更改,但由于函数是 运行 我的控制台日志,但不是我的渲染,一定是我遗漏了什么。
import React, { useEffect } from 'react';
function Report( { weatherData, units }) {
let windUnits = 'mph';
useEffect(() => {
units == 'imperial' ? windUnits = 'mph' : windUnits = 'km/h';
console.log('units updated');
}, [ weatherData ]);
return (
<p id="wind">{ `${ weatherData.wind.speed }${ windUnits } ${ getWindDirection(weatherData.wind.deg) }`}</p>
)
}
export default Report;
单位来自父组件,可以通过两个按钮更改以接收不同的测量数据。 weatherData 是从 api 接收到的数据,当 api 被调用并且数据发生变化时,windUnits 应该根据指定的单位类型发生变化。
目前,虽然 console.log 有效并且正确的单位类型从父组件打印到控制台,但屏幕上的文本不会更改以匹配它。
由于只要 props (weatherData
, units
) 发生变化,组件就会重新渲染,因此您不需要使用效果。只需将正确的单位分配给 windUnits
:
const { useState } = React;
const getWindDirection = x => x;
const Report = ({ weatherData, units }) => {
const windUnits = units == 'imperial' ? 'mph' : 'km/h';
return (
<p id="wind">{ `${ weatherData.wind.speed }${ windUnits } ${ getWindDirection(weatherData.wind.deg) }`}</p>
);
};
const Demo = () => {
const [units, setUnits] = useState('imperial');
return (
<div>
<button onClick={() => setUnits('imperial')}>imperial</button>
<button onClick={() => setUnits('metric')}>metric</button>
<Report weatherData={{ wind: { speed: 10, deg: 45 }}} units={units} />
</div>
)
};
ReactDOM.render(
<Demo />,
demo
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="demo"></div>
如果您只想在 windData
更改时重新渲染组件,您可以使用 useEffect
和 useState
。 useEffect
处理副作用,不重新渲染组件,对变量的更改将在下一次渲染时丢失。 useState
另一方面将重新渲染组件。
const { useState, useEffect } = React;
const getWindDirection = x => x;
const Report = ({ weatherData, units }) => {
const [windUnits, setWindUnits] = useState('mph');
useEffect(() => {
setWindUnits(units == 'imperial' ? 'mph' : 'km/h');
}, [weatherData]);
return (
<p id="wind">{ `${ weatherData.wind.speed }${ windUnits } ${ getWindDirection(weatherData.wind.deg) }`}</p>
);
};
const windData = { wind: { speed: 10, deg: 45 }};
const Demo = () => {
const [units, setUnits] = useState('imperial');
const [data, setData] = useState(windData);
const changeSpeed = () => setData({ ...data, wind: { ...data.wind, speed: Math.random() * 100 }});
return (
<div>
<button onClick={() => setUnits('imperial')}>imperial</button>
<button onClick={() => setUnits('metric')}>metric</button>
<button onClick={changeSpeed}>Change speed</button>
<Report weatherData={data} units={units} />
</div>
)
};
ReactDOM.render(
<Demo />,
demo
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="demo"></div>
另一种选择是将 React.memo 与 areEqual
回调一起使用,并且只检查 weatherData
是否相等:
const { useState, memo } = React;
const getWindDirection = x => x;
const Report = memo(({ weatherData, units }) => {
const windUnits = units == 'imperial' ? 'mph' : 'km/h';
return (
<p id="wind">{ `${ weatherData.wind.speed }${ windUnits } ${ getWindDirection(weatherData.wind.deg) }`}</p>
);
}, ({ weatherData: prev }, { weatherData: current }) => prev === current);
const windData = { wind: { speed: 10, deg: 45 }};
const Demo = () => {
const [units, setUnits] = useState('imperial');
const [data, setData] = useState(windData);
const changeSpeed = () => setData({ ...data, wind: { ...data.wind, speed: Math.random() * 100 }});
return (
<div>
<button onClick={() => setUnits('imperial')}>imperial</button>
<button onClick={() => setUnits('metric')}>metric</button>
<button onClick={changeSpeed}>Change speed</button>
<Report weatherData={data} units={units} />
</div>
)
};
ReactDOM.render(
<Demo />,
demo
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="demo"></div>