反应本性:在“两个底部”标签导航屏幕上使用相同的组件。

发布于 2025-02-12 06:57:21 字数 2800 浏览 0 评论 0原文

我有两个名为 todos 完成的屏幕。我使用底部选项卡导航器向它们显示。

<Tab.Navigator
      screenOptions={({route}) => ({
        headerShown: false,
        tabBarIcon: ({focused, color, size}) => {
          let iconName = '';
          size = focused ? 25 : 20;
          if (route.name === 'To-Do') {
            iconName = 'clipboard-list';
          } else if (route.name === 'Done') {
            iconName = 'clipboard-check';
          }

          return <FontAwesome5Icon name={iconName} size={size} color={color} />;
        },
        tabBarActiveTintColor: '#0080ff',
        tabBarInactiveTintColor: '#777777',
        tabBarLabelStyle: {fontSize: 15, fontWeight: 'bold'},
      })}>
      <Tab.Screen name="To-Do" component={Todos} />
      <Tab.Screen name="Done" component={Done} />
    </Tab.Navigator>

但是,这两个屏幕几乎彼此相同,随着 data flatlist 组件的属性的变化。这就是为什么要删除重复性,我一直在考虑在两个屏幕上使用单个组件 todos

当我尝试这样做时,我会注意到 todos 屏幕作为空屏幕呈现,而完成屏幕使用所需的数据正确呈现。控制台日志确实在 todos 上显示一个空数组。如果我对代码进行随机更改并保存,则在自动刷新后,我会观察到它可以正确加载数据。我正在使用路由。名称检查屏幕名称。 todos 屏幕的代码如下:

import stuff...
...
const Todos = ({navigation}: TodosPageProps) => {
  const dispatch = useAppDispatch();
  const {todos}: {todos: TodoInterface[]} = useAppSelector(
    state => state.todoReducer,
  );
  const route = useRoute<RouteProp<RootTabParamList, 'To-Do' | 'Done'>>();
  const [data, setData] = useState<TodoInterface[]>([]);

  useEffect(() => {
    loadTodos();
    console.log('bruh');
  }, []);

  const loadTodos = () => {
    AsyncStorage.getItem('todos').then(fetchedTodos => {
      const parsedTodos: TodoInterface[] = JSON.parse(fetchedTodos || '[]');
      dispatch(setAllTodo(parsedTodos));

      // *************************** START *************************************
      if (route.name === 'To-Do') {
        const filteredData = todos.filter(todo => todo.done !== true);
        console.log('aisi', filteredData);
        setData(filteredData);
      } else if (route.name === 'Done') {
        const filteredData = todos.filter(todo => todo.done === true);
        setData(filteredData);
      }
      // *************************** END *************************************
    });
  };
... some other methods
...

  return (
    <HideKeyboard>
      <View style={styles.body}>
        <FlatList
          data={data}
          ...other props
          ...
        />
      </View>
    </HideKeyboard>
  );
};

标记区域标记区域的星(*)标记区域显示了我在屏幕上添加的最新和有问题的代码以删除重复。有帮助吗?

I have two screens named Todos and Done. I am showing them using Bottom Tab Navigator.

<Tab.Navigator
      screenOptions={({route}) => ({
        headerShown: false,
        tabBarIcon: ({focused, color, size}) => {
          let iconName = '';
          size = focused ? 25 : 20;
          if (route.name === 'To-Do') {
            iconName = 'clipboard-list';
          } else if (route.name === 'Done') {
            iconName = 'clipboard-check';
          }

          return <FontAwesome5Icon name={iconName} size={size} color={color} />;
        },
        tabBarActiveTintColor: '#0080ff',
        tabBarInactiveTintColor: '#777777',
        tabBarLabelStyle: {fontSize: 15, fontWeight: 'bold'},
      })}>
      <Tab.Screen name="To-Do" component={Todos} />
      <Tab.Screen name="Done" component={Done} />
    </Tab.Navigator>

But these two screens are almost identical to each other with a change in the data property of FlatList component. That's why to remove duplicity I was thinking to use a single component Todos on both screens.

When I was trying to do that I notice Todos screen renders as an empty screen while the Done screen renders properly with the desired data. The console log indeed shows an empty array on Todos. If I make a random change in the code and save it, then after the automatic refresh I observe that it loads the data correctly. I am using route.name to check the screen name. The code for Todos screen is as follows:

import stuff...
...
const Todos = ({navigation}: TodosPageProps) => {
  const dispatch = useAppDispatch();
  const {todos}: {todos: TodoInterface[]} = useAppSelector(
    state => state.todoReducer,
  );
  const route = useRoute<RouteProp<RootTabParamList, 'To-Do' | 'Done'>>();
  const [data, setData] = useState<TodoInterface[]>([]);

  useEffect(() => {
    loadTodos();
    console.log('bruh');
  }, []);

  const loadTodos = () => {
    AsyncStorage.getItem('todos').then(fetchedTodos => {
      const parsedTodos: TodoInterface[] = JSON.parse(fetchedTodos || '[]');
      dispatch(setAllTodo(parsedTodos));

      // *************************** START *************************************
      if (route.name === 'To-Do') {
        const filteredData = todos.filter(todo => todo.done !== true);
        console.log('aisi', filteredData);
        setData(filteredData);
      } else if (route.name === 'Done') {
        const filteredData = todos.filter(todo => todo.done === true);
        setData(filteredData);
      }
      // *************************** END *************************************
    });
  };
... some other methods
...

  return (
    <HideKeyboard>
      <View style={styles.body}>
        <FlatList
          data={data}
          ...other props
          ...
        />
      </View>
    </HideKeyboard>
  );
};

The star (*) sign marked area shows the newest and problematic code that I added on the screen to remove duplicity. Any help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

那些过往 2025-02-19 06:57:21

这似乎是一个渲染错误。 (在更改选项卡时,组件不会再次呈现)

一个可能的解决方案可以是验证使用效率并设置状态的路由,因此,每当状态更改时,组件将重新渲染
我们将使用该状态在LOADTODOS函数中验证

import React from 'react'

export const LoadTodos = () => {


const [selectedPage, setselectedPage] = useState('Done')


    useEffect(() => {
        if (route.name === 'To-Do' && selectedPage === 'Done'){
            setselectedPage('To-Do')
        }
        if (route.name === 'Done' && selectedPage === 'To-Do'){
            setselectedPage('Done')
        }
        console.log('bruh');
      }, []);


      const loadTodos = () => {
        AsyncStorage.getItem('todos').then(fetchedTodos => {
          const parsedTodos: TodoInterface[] = JSON.parse(fetchedTodos || '[]');
          dispatch(setAllTodo(parsedTodos));
    
          // *************************** START *************************************
          if (selectedPage === 'To-Do') {
            const filteredData = todos.filter(todo => todo.done !== true);
            console.log('aisi', filteredData);
            setData(filteredData);
          } else if (selectedPage === 'Done') {
            const filteredData = todos.filter(todo => todo.done === true);
            setData(filteredData);
          }
          // *************************** END *************************************
        });
      };
  return (
    <HideKeyboard>
      <View style={styles.body}>
        <FlatList
          data={data}
          ...other props
          ...
        />
      </View>
    </HideKeyboard>
  )
}
export default loadTodos

This seems to be a render error. (the component isnt rendering again when the tab is changed)

A posible solution could be to validate the route in the useEffect and setting a state, therefore whenever the state changes the component will re-render
and we will use the state to validate in loadTodos function

import React from 'react'

export const LoadTodos = () => {


const [selectedPage, setselectedPage] = useState('Done')


    useEffect(() => {
        if (route.name === 'To-Do' && selectedPage === 'Done'){
            setselectedPage('To-Do')
        }
        if (route.name === 'Done' && selectedPage === 'To-Do'){
            setselectedPage('Done')
        }
        console.log('bruh');
      }, []);


      const loadTodos = () => {
        AsyncStorage.getItem('todos').then(fetchedTodos => {
          const parsedTodos: TodoInterface[] = JSON.parse(fetchedTodos || '[]');
          dispatch(setAllTodo(parsedTodos));
    
          // *************************** START *************************************
          if (selectedPage === 'To-Do') {
            const filteredData = todos.filter(todo => todo.done !== true);
            console.log('aisi', filteredData);
            setData(filteredData);
          } else if (selectedPage === 'Done') {
            const filteredData = todos.filter(todo => todo.done === true);
            setData(filteredData);
          }
          // *************************** END *************************************
        });
      };
  return (
    <HideKeyboard>
      <View style={styles.body}>
        <FlatList
          data={data}
          ...other props
          ...
        />
      </View>
    </HideKeyboard>
  )
}
export default loadTodos
秋叶绚丽 2025-02-19 06:57:21

我通过在 loadtodos 方法上用parsedtodos替换TODOS来解决此问题。我想初始渲染时,空的redux商店托多斯(Todos)并未在dispatch上的parsedtodos(setalltodo(parsed))的数据填充。它将空存储转移到了过滤器方法。这就是为什么屏幕空白的原因。我的固定代码:

const loadTodos = async () => {
    const fetchedTodos = await AsyncStorage.getItem('todos');
    const parsedTodos: TodoInterface[] = JSON.parse(fetchedTodos || '[]');
    if (parsedTodos.length !== todos.length) {
      dispatch(setAllTodo(parsedTodos));
    }
    // *************************** START *************************************
    if (route.name === 'To-Do') {
      const filteredData = parsedTodos.filter(todo => todo.done !== true);
      setData(filteredData);
    } else if (route.name === 'Done') {
      const filteredData = parsedTodos.filter(todo => todo.done === true);
      setData(filteredData);
    }
    // *************************** END *************************************
  };

I have fixed this problem by replacing todos with parsedTodos on loadTodos method. I guess on initial render the empty redux store todos was not populated with the data from parsedTodos on dispatch(setAllTodo(parsed)). It passed empty store to the filter method. That's why the screen was blank. My fixed code:

const loadTodos = async () => {
    const fetchedTodos = await AsyncStorage.getItem('todos');
    const parsedTodos: TodoInterface[] = JSON.parse(fetchedTodos || '[]');
    if (parsedTodos.length !== todos.length) {
      dispatch(setAllTodo(parsedTodos));
    }
    // *************************** START *************************************
    if (route.name === 'To-Do') {
      const filteredData = parsedTodos.filter(todo => todo.done !== true);
      setData(filteredData);
    } else if (route.name === 'Done') {
      const filteredData = parsedTodos.filter(todo => todo.done === true);
      setData(filteredData);
    }
    // *************************** END *************************************
  };
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文