【问题标题】:Setting variable with ReactJS's useState hook does not work使用 ReactJS 的 useState 挂钩设置变量不起作用
【发布时间】:2019-11-27 14:05:58
【问题描述】:

我试图在 API 调用后使用useState 设置一个变量,但它不起作用。通过reactotron调试,他做了API调用,但他没有设置变量。

export default function Forecast({ navigation }) {
  const [cityData, setCityData] = useState([]);
  const idNavigation = navigation.state.params.cityData.woeid;

  async function loadCityData(cityID) {
    const response = await api.get(`${cityID}`);
    setCityData([response]);
    console.tron.log(cityData);
  }

  useEffect(() => {
    if (idNavigation) {
      loadCityData(idNavigation);
    }
    return () => {};
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [idNavigation]);

  return <Text>Forecast Weather</Text>;
}

Forecast.propTypes = {
  navigation: PropTypes.shape({
    state: PropTypes.object,
  }).isRequired,
};

【问题讨论】:

  • console 中是否有任何错误?确保您在response 中获取数据。
  • 代码看起来不错。您能否验证来自 API 的 response 是否有一些数据?
  • 是的,也许是您正在发出的 HTTP 请求。请检查控制台。
  • 响应没问题。问题是 setState,它没有设置值。
  • 日志错误:可能是未处理的 Promise Rejectior,类型错误:未定义不是对象(正在评估响应数据)

标签: reactjs react-native react-hooks


【解决方案1】:

在 React 中设置状态大部分是异步的,如果您尝试立即对它们进行控制台记录,则对状态的更改可能不可见。使用钩子执行此操作的推荐方法是检查 useEffect 中的更新状态:

 async function loadCityData(cityID) {
  const response = await api.get(`${cityID}`);
  setCityData([response]);
}

// Track cityData and log the changes to it
useEffect(() => {
  console.log(cityData);
}, [cityData]);

// Rest of the code
// ...

【讨论】:

  • 这不正是用户也在做的事情吗?
  • 用户所做的是设置数据,然后立即调用console.log,返回旧状态。
  • 我试过了,但没用。我不明白。在代码中,await doent 起作用
  • 日志错误:可能是未处理的 Promise Rejectior,类型错误:未定义不是对象(正在评估响应数据)
  • 这是 api 的问题,可能应该在单独的问题中提出。
【解决方案2】:

嗯,我认为这可能是 reactotron 或 api 问题。 试试吧

const [cityData, setCityData] = useState('foo');

...

return <Text>{JSON.stringify(cityData)}</Text>;

如果您的问题来自 reactron,那么您可以看到来自 API 的响应。

【讨论】:

【解决方案3】:

因为useState是异步函数。

    setCityData([response]); // asynchronous function so not set the new data to state yet.
    console.tron.log(cityData);// so you get the old data.

查看此示例

const Forecast = ({ idNavigation }) => {
    const [cityData, setCityData] = React.useState([]);
  
    function loadCityData(cityID) {
      setTimeout(() => {
        setCityData([1,2,3,4,5]);
        console.log("this is old data", cityID, cityData); // because useState is asynchronous function
      }, 2000);
    }
  
    React.useEffect(() => {
      if (idNavigation) {
        console.log("load ", idNavigation);
        loadCityData(idNavigation);
      }
    }, [idNavigation]);
    
    React.useEffect(() => {
      if(cityData.length > 0) {
        console.log("this is new data", cityData);
      }
    }, [cityData]); // when cityData changed and component mounted, this function called.
  
    return <div>Forecast Weather</div>;
  }
  
  class App extends React.Component {
    state = {
      id: 1,
    }
    
    componentDidMount() {
      setTimeout(() => {
        this.setState({id: 2});
      }, 2000);
    }
  
    render() {
      return (
        <div>
          <Forecast idNavigation={this.state.id}/>
        </div>
      );
    }
  }
  
  ReactDOM.render( <App / > , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0-alpha.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0-alpha.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>

解决方案

如果您使用类组件,您可以使用setState() 函数的回调。 但如果您使用功能组件,则不能使用回调。
所以你应该使用useEffect()来解决这个问题。

【讨论】:

    猜你喜欢
    • 2021-09-04
    • 1970-01-01
    • 2023-02-24
    • 2020-05-19
    • 2021-03-10
    • 2020-02-22
    • 2019-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多