首页 > 解决方案 > 如何反应原生重新渲染 Flatlist?

问题描述

如何反应原生重新渲染 Flatlist?

使用 Effect 检查 tagId 的数据并打开一个新页面,直到 tagId 存在。

使用 use Effect 导入的数据不会传递给 renderItem,而只会传递第一页的数据。

如何将更新的数据从 useEffect 转发到 renderItem?

app.tsx

const App: () => Node = () => {
  const Stack = createNativeStackNavigator();
  const [accessToken, setAccessToken] = useState("");
  const [isSearchHidden, setIsSearchHidden] = useState(false);
  const [isHomeHidden, setIsHomeHidden] = useState(false);
  const [id, setId] = useState("");
  const [tagId, setTagId] = useState("");
  const [chargeAmount, setChargeAmount] = useState("");

  const value = {
    setAccessToken: setAccessToken,
    isSearchHidden: isSearchHidden,
    setIsSearchHidden: setIsSearchHidden,
    isHomeHidden: isHomeHidden,
    setIsHomeHidden: setIsHomeHidden,
    id: id,
    setId: setId,
    tagId: tagId,
    setTagId: setTagId,
    chargeAmount: chargeAmount,
    setChargeAmount: setChargeAmount,
  };

  useEffect(() => {
    AsyncStorage.getItem("@user", (_: any, result: any) => {
      // console.log("user: ",result)
      if (result) {
        // result가 있을때만 accessToken 저장
        setAccessToken(result);
      }
    });
  }, []);

  const errorLink = onError(({ graphQLErrors, operation, forward }) => {
    if (graphQLErrors) {
      for (const err of graphQLErrors) {
        if (err.extensions?.code === "UNAUTHENTICATED") {
          operation.setContext({
            headers: {
              ...operation.getContext().headers,
              authorization: `Bearer ${getAccessToken(setAccessToken)}`,
            },
          });
          return forward(operation);
        }
      }
    }
  });

  const uploadLink = createUploadLink({
    uri: "https://backend03-team.codebootcamp.co.kr/team05",
    headers: {
      authorization: `Bearer ${accessToken}`,
    },
    credentials: "include",
  });

  const client = new ApolloClient({
    cache: new InMemoryCache(),
    link: ApolloLink.from([errorLink, uploadLink as unknown as ApolloLink]),
  });

  return (
    <GlobalContext.Provider value={value}>
      <ApolloProvider client={client}>
        <NavigationContainer>
          <Stack.Navigator screenOptions={{ headerShown: false }}>
            {accessToken ? (
              <Stack.Screen name="tabNavigator" component={TabNavigator} />
            ) : (
              <Stack.Screen name="Login" component={LoginNavigator} />
            )}
          </Stack.Navigator>
        </NavigationContainer>
      </ApolloProvider>
    </GlobalContext.Provider>
  );
};

export default App;

container

const ListContainer = () => {
  const [aaa, setAaa] = useState(1);

  const { data, fetchMore, refetch } = useQuery(FETCH_USED_ITEMS, {
    variables: {
      page: 1,
      isSoldout: false,
    },
  });

  useEffect(() => {
    console.log("9999", data);

    const result = data?.fetchUseditems.some((el) => {
      return el.tags[0] === tagId;
    });

    console.log("33332232111", result);
    console.log("989898", tagId);

    if (result === false) {
      onLoadMore();
    } else {
      return;
    }
    console.log("443432", aaa);
  }, [data?.fetchUseditems]);

  const { setId, id, setTagId, tagId } = useContext(GlobalContext);

  const onPressDetail = (el) => {
    setId(el._id);

    console.log("555", el._id);
    console.log("433", id);
  };

  const onPressListCategory = (value) => {
    setTagId(value);
  };

  const onLoadMore = () => {
    // if (!data) {
    //   return;
    // }

    fetchMore({
      variables: {
        page: Math.ceil(data?.fetchUseditems.length / 10) + 1,
      },
      updateQuery: (prev, { fetchMoreResult }) => {
        return {
          fetchUseditems: [
            ...prev.fetchUseditems,
            ...fetchMoreResult.fetchUseditems,
          ],
        };
      },
    });
  };

  return (
    <ListUI
      data={data}
      onPressDetail={onPressDetail}
      onPressListCategory={onPressListCategory}
      onLoadMore={onLoadMore}
      setAaa={setAaa}
      aaa={aaa}
      fetchMore={fetchMore}
      refetch={refetch}
    />
  );
};
presenter

const ListUI = (props) => {
  const { tagId, setTagId, setAaa } = useContext(GlobalContext);

  const navigation = useNavigation();

  const renderItem = ({ item }: any) => {
    console.log("***********************", item);

    return (
      <>
        {item.tags[0]?.includes(tagId) && (
          <DetailProductWrapper key={item._id}>
            <ProductImageWrapper
              onPress={() =>
                navigation.navigate("상품 상세보기", {
                  id: props.onPressDetail(item),
                })
              }
            >
              <ProductImage
                source={{
                  uri: `https://storage.googleapis.com/${item.images[0]}`,
                }}
              />
            </ProductImageWrapper>
            <InfoWrapper>
              <InfoTextWrapper>
                <InfoTitle>{item.name}</InfoTitle>
                <InfoPrice>{item.price}원&lt;/InfoPrice>
              </InfoTextWrapper>
              <InfoFavoriteImage
                source={require("../../../public/images/list/infofavorite.png")}
              />
            </InfoWrapper>
          </DetailProductWrapper>
        )}
      </>
    );
  };

  console.log("================", props.data);
  console.log("6666", props.aaa);
  return (
    <ListView>
      <HeaderAnimation onPressListCategory={props.onPressListCategory} />
      <FlatList
        data={props.data?.fetchUseditems}
        renderItem={renderItem}
        keyExtractor={(item) => item.id}
        onEndReached={props.onLoadMore}
        extraData={props.data}
        onEndReachedThreshold={0.8}
      ></FlatList>
    </ListView>
  );
};

数据控制台捕获 在此处输入图像描述

renderItem 控制台捕获 在此处输入图像描述

标签: react-nativereact-native-flatlist

解决方案


通过将 extraData={this.state} 传递给 FlatList,我们确保 FlatList 本身会在状态更改时重新渲染。如果不设置这个 prop,FlatList 将不知道它需要重新渲染任何项目,因为它是一个 PureComponent,并且 prop 比较不会显示任何更改。

平面列表文档


推荐阅读