【问题标题】:React native: useState not updating correctly反应原生:useState 没有正确更新
【发布时间】:2021-08-05 15:31:16
【问题描述】:

我是新来的原生反应,目前正在与无限滚动列表视图作斗争。这是一个日历列表,需要根据所选公司进行更改(作为道具给出)。问题是:prop(以及 myCompany 状态已更改,但在 _loadMoreAsync 方法中,prop.companymyCompany 都保留了它们的初始值。

import * as React from 'react';
import { FlatList } from 'react-native';
import * as Api from '../api/api';
import InfiniteScrollView from 'react-native-infinite-scroll-view';

function CalenderFlatList(props: { company: any }) {
  const [myCompany, setMyCompany] = React.useState(null);
  const [data, setData] = React.useState([]);
  const [canLoadMore, setCanLoadMore] = React.useState(true);
  const [startDate, setStartDate] = React.useState(undefined);

  let loading = false;

  React.useEffect(() => {
    setMyCompany(props.company);
  }, [props.company]);

  React.useEffect(() => {
    console.log('set myCompany to ' + (myCompany ? myCompany.name : 'undefined'));
    _loadMoreAsync();
  }, [myCompany]);

  async function _loadMoreAsync() {
    if ( loading )
      return;

    loading = true;

    if ( myCompany == null ) {
      console.log('no company selected!');
      return;
    } else {
      console.log('use company: ' + myCompany.name);
    }

    Api.fetchCalendar(myCompany, startDate).then((result: any) => {
      // code is a little more complex here to keep the already fetched entries in the list...
      setData(result);

      // to above code also calculates the last day +1 for the next call
      setStartDate(lastDayPlusOne);

      loading = false;
    });
  }

  const renderItem = ({ item }) => {
    // code to render the item
  }

  return (
    <FlatList
      data={data}
      renderScrollComponent={props => <InfiniteScrollView {...props} />}
      renderItem={renderItem}
      keyExtractor={(item: any) => '' + item.uid }
      canLoadMore={canLoadMore}
      onLoadMoreAsync={() => _loadMoreAsync() }
    />
  );
}

我不明白为什么myCompany_loadMoreAsync 中根本没有更新,而startDate 正确更新并准确加载日历的下一个条目。

在 prop company 更改后,我希望得到以下输出:

将 myCompany 设置为 companyName

使用公司公司名称

但是我得到了:

将 myCompany 设置为 companyName

没有选择公司!

我尝试稍微减少代码以将其剥离到最重要的部分。对此有何建议?

【问题讨论】:

  • 这没有意义。如果这是真的,您可以将公司转入_loadMoreAsync(company)。但我认为这不可能发生。因为您可以将所有算法移至React.useEffect
  • 你对什么是反应状态有点困惑,我是说因为适当的加载是用错误的方法管理的。也许如果您可以通过最小可重现示例重现问题,我们可以帮助您更好地理解您的问题
  • @windmaomao 没错,如果我将所有内容都移到React.useEffect 中,它就像一个魅力。如果我将company 传递给_loadMoreAsync,它也可以工作。问题是我还需要从React.useEffect 外部访问_loadMoreAsync。否则 FlatList 的 onLoadMoreAsync 属性将无权访问。所以我的例子不正确,因为在更改props.company 之后,我可以设法产生正确的输出,但是如果我从另一个地方调用_loadMoreAsync,它仍然使用myCompany 的初始值。
  • 我认为问题只出现在FlatListonLoadMoreAsync属性中。这有可能使用某种缓存吗?如果我用onLoadMoreAsync={() =&gt; { console.log(myCompany); }} 替换它,它只会打印出初始值,但不会更新myCompany 的当前状态。

标签: reactjs react-native use-effect use-state


【解决方案1】:

Google for useEffect 陈旧关闭。

当从 useEffect 调用该函数时,它是从一个陈旧的上下文中调用的 - 这显然是一个 javascript 功能 :) 所以基本上你遇到的行为是预期的,你需要找到一种解决方法。

一种方法可能是将一个(可选)参数添加到您从 useEffect 传递的 _loadMoreAsync。如果这个参数是未定义的(从其他地方调用时会被定义),那么使用 state 中的值。

【讨论】:

    【解决方案2】:

    试试

    <FlatList
        data={data}
        renderScrollComponent={props => <InfiniteScrollView {...props} />}
        renderItem={renderItem}
        keyExtractor={(item: any) => '' + item.uid }
        canLoadMore={canLoadMore}
        onLoadMoreAsync={() => _loadMoreAsync() }
        extraData={myCompany}
     />
    

    如果您的 FlatList 依赖于状态变量,则需要将该变量传递给 extraData 属性以触发列表的重新呈现。更多信息here

    【讨论】:

      【解决方案3】:

      为这个问题睡了两晚后,我自己解决了。原因是另一段使用 React.useCallback() 的代码的影响。并且由于“useCallback 将返回回调的记忆版本,只有在其中一个依赖项发生更改时才会更改”(https://reactjs.org/docs/hooks-reference.html#usecallback),因此代码使用变量的旧(或初始)状态。

      从头开始创建整个页面后,我发现这就是导致这种行为的原因。

      【讨论】:

        猜你喜欢
        • 2017-03-08
        • 1970-01-01
        • 2021-10-05
        • 2021-08-20
        • 2019-06-07
        • 1970-01-01
        • 2020-07-17
        • 2021-07-22
        • 1970-01-01
        相关资源
        最近更新 更多