组件未在useState数组更改时重新呈现

时间:2020-08-22 21:03:02

标签: react-native react-hooks use-state

我在FeedScreen.js上显示的“ tweet”卡上有一个收藏夹按钮。

~~~~~~~~~ IMPORTS SNIP ~~~~~~~~~

function FeedScreen(props) {
  const [feed, setFeed] = useState([]);
  const [favorites, setFavorite] = useState([]);
  const [refreshing, setRefreshing] = useState(false);
  useEffect(() => {
    loadFeed(0, 4);
  }, []);

  const loadFeed = async (last_id = 0, limit = 1) => {
    setRefreshing(true);
    const response = await tweetsApi.getTweets(last_id, limit);
    if (response.ok) {
      setFeed(response.data["data"].concat(feed));
    } else {
      console.log(response.problem);
    }
    setRefreshing(false);
  };

  const handleBookmark = async (item_id) => {
    const response = await tweetsApi.toggleBookmark(item_id);
    if (response.ok) {
      console.log("ok response");
      setFavorite(favorites.concat(item_id));
// I've tried this as well
// setFavorite([...favorites].concat(item_id));
// but in vain
      console.log(favorites);
    }
  };

  return (
    <Screen style={styles.screen}>
      <FlatList
        data={feed}
        keyExtractor={(tweet) => {
          return tweet.id.toString();
        }}
        renderItem={({ item }) => (
~~~~~~~~~ SNIP ~~~~~~~~~
            <CardFooter
              style={{ marginLeft: 20 }}
              item={item}
              onPress={handleBookmark}
            />
          </View>
        )}
        ItemSeparatorComponent={ListItemSeparator}
        refreshing={refreshing}
        onRefresh={() => {
          loadFeed(feed[0]["id"], 2);
        }}
      />
    </Screen>
  );
}

~~~~~~~~~ SNIP ~~~~~~~~~

这是CardFooter.js

~~~~~~~~~ SNIP ~~~~~~~~~

function CardFooter({ item, onPress }) {
  return (
      <View style={styles.bookmark}>
        <TouchableOpacity
          onPress={() => {
            return onPress(item.id);
          }}
        >
          {item.bookmarked && (
            <FontAwesome name="bookmark" size={24} color="red" />
          )}
          {!item.bookmarked && (
            <FontAwesome5 name="bookmark" size={24} color="black" />
          )}
        </TouchableOpacity>
      </View>
    </View>
  );
}
export default CardFooter;
~~~~~~~~~ SNIP ~~~~~~~~~

但是该组件似乎没有重新呈现。 我看过这些:

  1. react-component-not-re-rendering-after-using-usestate-hook
  2. 类似的here
  3. Another one 17 days back - why-usestate-is-not-re-rendering
  4. usestate-not-re-rendering-when-updating-nested-object

所有这些以及其他类似的东西,每个都指向一个事实,即应该创建一个新数组,以便react重新渲染它。

更新

console.log输出

是,console.log正在打印数组,尽管先前是一个值。这是因为useState是异步的,因此它没有打印实时数组。因此,当第二次调用此方法时,它将显示一个item_id(上一个)添加到favorites

1 个答案:

答案 0 :(得分:0)

我最后通过管理组件本身中的状态解决了这个问题。

不确定这是否是执行此操作的“正确方法”,但请阅读here (how-to-add-a-simple-toggle-function-in-react-native) ,这是您可以执行此操作的方式。

因此,现在书签组件从顶级组件(FeedScreen.js)获得响应:

const handleBookmark = async (item_id) => {
    const response = await tweetsApi.toggleBookmark(item_id);
    if (response.ok) {
      return true;
    } else {
      return false;
    }
  };

并更改CardFooter.js,即书签组件所在的位置。

function CardFooter({ item, onPress }) {
  const [favorite, setFavorite] = useState(item.bookmarked);
  return (
      <View style={styles.bookmark}>
        <TouchableOpacity
          onPress={async () => {
            let response = await onPress(item.id);
            if (response) {
              setFavorite(!favorite);
            } else {
              alert("Some error occurred");
            }
          }}
        >
          {favorite && <FontAwesome name="bookmark" size={24} color="red" />}
          {!favorite && (
            <FontAwesome5 name="bookmark" size={24} color="black" />
          )}
        </TouchableOpacity>
      </View>
    </View>
  );
}

关注事项

我有点担心如何处理此组件中的响应。

我应该在底部组件中处理async操作吗?