每当特定状态或道具更新时,我都试图使用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工作并且从父组件将正确的单元类型打印到控制台时,屏幕上的文本不会更改以匹配它。
答案 0 :(得分:4)
由于每当道具(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>