Вкладки категорий React Native - каждая вкладка отображает разные категории

Nov 29 2020

В настоящее время я пытаюсь реализовать экран просмотра, где пользователи могут выбрать определенную категорию из ScrollView, который отображает сообщения, связанные с этой категорией.

Мой api получает все данные поста из бэкэнда, и для каждого поста у меня есть параметр categoryId.

Я пытаюсь сделать, например, одну из моих категорий - спорт. когда пользователь выбирает вкладку спорта, должен отображаться плоский список со всеми сообщениями о спорте.

В этой текущей реализации у меня есть вкладки категорий, и когда я выбираю любую из вкладок, отображаются все сообщения, а не сообщения для этой конкретной категории.

Вот мой код:

function SearchScreen({ navigation }) {
const [posts, setPosts] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);

const loadPosts = async () => {
setLoading(true);
const response = await postsApi.getPosts(page);
setLoading(false);

if (!response.ok) return setError(true);

setError(false);
setPosts(response.data);
};

const[page,setPage]=useState(0);

useEffect(() => {
loadPosts();
 }, []);

const categories = [
{
  label: "Sports",
  id: 1,
},
{
  label: "Fashion",
  id: 2,
},
{
  label: "News",
  id: 3,
   },
  ];

 const[label,setLabel]=useState('Sports')
 const[dataList,setDataList]=useState(posts)

const setLabelFilter=label=>{
setLabel(label)
}

return (
<>
  <ActivityIndicator visible={loading} />
  <Screen style={styles.screen}>
    {error && (
      <>
        <View style={styles.error}>
          <AppText>Could not retrieve posts from server.</AppText>
          <AppButton title="Retry" onPress={loadPosts} />
        </View>
      </>
    )}
    <ScrollView 
    horizontal 
    style={{flexDirection:"row",
    alignContent:"center",
    width:Dimensions.get('window').width/1.05,
    marginBottom:20,
    }} 
    showsHorizontalScrollIndicator={false}
    >
    {categories.map(e=>(
            <TouchableOpacity 
            style={[
                {paddingHorizontal:10,paddingBottom:10},
                label===e.label && 
                {borderBottomWidth:3,
                borderBottomColor:colors.primary,
                borderRadius:2,
            }
                ]} 
                onPress={()=>setLabelFilter(e.label)}
                >
            <AppText style={[{fontWeight:"500",color:colors.medium},label===e.label && 
{color:colors.primary,fontWeight:"700"}]}>{e.label}</AppText>
            </TouchableOpacity>
    ))}
    </ScrollView>

    <FlatList
      data={posts} // to have all the data
      keyExtractor={(post) => post.id.toString()}
      renderItem={({ item,index }) => (
        <Card
          title={item.title}
          subTitle={item.subTitle}
          onPress={() => navigation.navigate(routes.POST_DETAILS, {post:item,index})}            
  />
      )}
    />
  </Screen>
</> 
);
}

Когда я делаю console.log (сообщения), вот как выглядит мой ответ:

Object {
"Category": Object {
  "id": 1,
  "name": "Sports",
},
"categoryId": 3,
"createdAt": "2020-11-18T13:43:19.616Z",
"deletedAt": null,
"id": 506,
"subtTitle": "test",
"title": "test",
"updatedAt": "2020-11-23T06:57:44.150Z",
"userId": 1,
 },

Я подумал о том, чтобы изменить свой вызов API, чтобы получить категорию по ее идентификатору, а затем включить все сообщения для каждой конкретной категории, но это не сработало, поэтому я пошел с вызовом API, чтобы получить все сообщения.

Обновить

 const[label,setLabel]=useState('Sports')

 const setLabelFilter=label=>{
setLabel(label)
  }

 const [currentCategoryId, setCurrentCategoryId] = useState()

 const toggleBrands = (categoryId) => {
 setCurrentCategoryId(categoryId)
 setLabel(label)
   };

 return(
 <ScrollView 
    horizontal 
    showsHorizontalScrollIndicator={false}
    >
    {categories.map(e=>(
            <TouchableOpacity 
                key={e.id}
                onPress={()=>{toggleBrands(e.id),
                setLabelFilter(e.label)}}
                selected={e.id === currentCategoryId}
                >
            <AppText>{e.label}</AppText>
            </TouchableOpacity>
    ))}
    </ScrollView>

    <FlatList
      data={currentCategoryId ? 
posts.filter(post=>post.categoryId===currentCategoryId
        ):posts}

Я пробовал следующий код, может кто-нибудь сказать мне, правильный он или нет?

Ответы

KenLee Nov 29 2020 at 13:20

В качестве примера предположим, что вы сначала щелкаете элемент в Flatlist (показывающий все категории) на экране A, а затем система перейдет на экран B (с Flatlist, показывающим только элементы выбранной категории)

Обычный метод - динамически отображать только данные выбранной категории, например, с помощью сценария php (в данном примере это sjson.php).

Для экрана A это будет так:

Экран Функция GetFlatListItem:

GetFlatListItem (fruit_name) {
   this.props.navigation.navigate('ScreenB', {unitserial: fruit_name}) 
   } 

Экран Flatlist может быть таким:


          data={ this.state.dataSource }
          
          ItemSeparatorComponent = {this.FlatListItemSeparator}
 
          renderItem={({item}) => 
          
 <View style={{flex: 1, flexDirection: 'row', justifyContent:'flex-start'}}>
<Text  onPress={this.GetFlatListItem.bind(this, item.serial)} > 
          {item.ok}</Text>
</View>
 

Для экрана B это будет так:

const enstring='https://www.test.com/sjson.php?serial=' + this.props.route.params.unitserial ;


       return fetch(enstring)
         .then((response) => response.json())
         .then((responseJson) => {
             

           this.setState({
             dataSource: responseJson
           }, function() {
             // In this block you can do something with new state.
           });
              
              
         })
         .catch((error) => {
           console.error(error);
         });
         }

и Flatlist может выглядеть так:

<FlatList
       data={ this.state.dataSource }

>

Обратите внимание, что вам нужно будет изменить свои коды в соответствии с вашими потребностями. Это всего лишь пример.

RajshekharYadav Nov 29 2020 at 14:07

Первое определение состояний:

      const [apiRespPonse, setApiRespone] = useState("");
  const [selectedTabData, setSelectedPost] = useState("");
  const [category, setCategory] = useState("Sports");

В вашем вызове api установите ответ:

const fetchAllPost = () => {
    
    setApiRespone([]);
      const newArr = apiRespPonse.filter(obj => obj.label===category);
            setSelectedPost(newArr)
  };

Для вашей опции рендеринга используйте фильтр для массива, чтобы получить данные выбранной вкладки:

 return (
    <View style={styles.app}>
      <View style={styles.header}>
     
          <View style={{ flexDirection: "row" }}>
         {categories.map((item, index) => {
          return <Text onPress={()=>{
            setCategory(categories[index])
            const newArr = apiRespPonse.filter(obj => obj.label===category);
            setSelectedPost(newArr)
          }} style={styles.title}>{item.label}</Text>;
        })}
        </View>
     
      </View>


<FlatList
data={selectedTabData}/>
    </View>
  );
};

Может быть, это поможет.

SaachiTech Nov 30 2020 at 07:31

Если я правильно понимаю, вы просто хотите обновить содержимое плоского списка с помощью выбранной категории. Я думаю, что код, который у вас есть до обновлений, делает все, что вам нужно, с небольшими обновлениями. Вот часть кода, которую вам просто нужно обновить

{categories.map((e,index)=>(
  <TouchableOpacity 
    ...
    style={[
      ...
      index===page && {
        borderBottomWidth:3,
        borderBottomColor:colors.primary,
        borderRadius:2,
    }]
    onPress={()=>{setPage(index)}}
  >
  ...
  </TouchableOpacity>
)}

Убедитесь, что postsApi.getPosts(page);возвращает правильные данные на основе данного pageпараметра.