我可以在React中使用useEffect来更新页面显示吗?

时间:2019-05-12 20:22:26

标签: javascript reactjs react-hooks

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

1 个答案:

答案 0 :(得分:4)

由于每当道具(weatherDataunits)发生变化时都会重新渲染组件,因此您无需使用效果。只需将正确的单位分配给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时才重新渲染组件,则可以将useEffectuseState一起使用。 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.memoareEqual回调一起使用,并且仅检查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>