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

Posted

技术标签:

【中文标题】如何反应原生重新渲染 Flatlist?【英文标题】:How to do react native re-render Flatlist? 【发布时间】:2021-12-28 01:51:03 【问题描述】:

如何做 react native 重新渲染 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원</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>
  );
;

数据控制台捕获 enter image description here

renderItem 控制台捕获 enter image description here

【问题讨论】:

【参考方案1】:

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

Flatlist Doc

【讨论】:

以上是关于如何反应原生重新渲染 Flatlist?的主要内容,如果未能解决你的问题,请参考以下文章

如何在反应原生中改变 <​​FlatList/> 的高度?

如何在反应原生中过滤FlatList中的项目

反应原生 Flatlist 导航

如何在反应原生的子组件上重新渲染父组件?

在 FlatList 反应原生“keyboardDismissMode”

状态变化时如何防止 FlatList 重新渲染