#reactjs #react-native #react-navigation
#reactjs #react-native #react-навигация
Вопрос:
Я пытаюсь поместить навигатор стека в другой навигатор стека следующим образом
const ProfileStack = createStackNavigator(
{
Profile: { screen: ProfileScreen },
Comment: { screen: CommentStack },
}
);
const CommentStack = createStackNavigator(
{
Comment: { screen: CommentScreen },
Profile: { screen: ProfileStack },
}
);
поскольку CommentStack объявлен после ProfileStack, я не могу достичь того, чего хочу.
Могу ли я каким-либо образом сделать то же самое, что и в react-navigation 4?
РЕДАКТИРОВАТЬ: я пытаюсь создать приложение для социальных сетей, и описанный выше способ не работает. В настоящее время я делаю это таким образом:
const ProfileStack = createStackNavigator(
{
Profile: { screen: ProfileScreen },
Comment: { screen: CommentScreen },
}
);
const CommentStack = createStackNavigator(
{
Comment: { screen: CommentScreen },
Profile: { screen: ProfileStack },
}
);
Но когда кто-то заходит в чей-то профиль и комментирует его / ее сообщение, а затем посещает профиль комментатора, react-native переходит обратно на экран профиля. Я хочу отправить в новый стек профилей, чтобы он мог работать в цикле. Извините, английский не мой родной язык
Комментарии:
1. Почему вы это пытаетесь? Я думаю, вы вообще не понимаете, как работает react navigation
2. Я действительно не понимаю, что вы пытаетесь здесь сделать. Эти навигаторы не могут одновременно иметь друг друга в качестве экранов. Не могли бы вы подробнее рассказать о варианте использования? Возможно, это делает его более понятным.
Ответ №1:
Как я упоминал в своем комментарии, у вас не может быть двух навигаторов, которые имеют друг друга в качестве экранов. У вас может быть один навигатор, у которого есть другой навигатор в качестве экрана. Но из того, что я понимаю из вашего вопроса, я не думаю, что есть даже необходимость в ProfileStack
и CommentStack
.
Я предлагаю вместо этого иметь один навигатор, который содержит CommentScreen
и ProfileScreen
, и позволить вашим данным определять, что показывать и куда идти. Вот некоторый код, который нужно показать, чтобы проиллюстрировать, что я имею в виду:
/* The users in your system identified by an id
and the comments they have on their profile */
const profileData = [
{
userId: 1,
comments: [
{ message: 'message from 2', commenter: 2 },
{ message: 'message from 3', commenter: 3 },
],
},
{
userId: 2,
comments: [{ message: 'message from 1', commenter: 1 }],
},
{
userId: 3,
comments: [{ message: 'message from 2', commenter: 2 }],
},
];
/* A simple profile screens that displays a user's profile
and that has a button to navigate to the comment page. */
const ProfileScreen = ({ navigation }) => {
const userId = navigation.getParam('userId');
return (
<View>
<Text>{`Profile of user ${userId}`}</Text>
<Button
title="go to comments"
onPress={() => {
navigation.push('Comment', { userId });
}}
/>
</View>
);
};
/* The comment screen shows all the comments a user has
and displays a button next to a comment to go to that
commenter's profile */
const CommentScreen = ({ navigation }) => {
const userId = navigation.getParam('userId');
return (
<View>
<Text>{`Comments of user ${userId}`}</Text>
{profileData
.filter((user) => user.userId == userId)[0]
.comments.map((comment) => {
return (
<View style={{ flexDirection: 'row' }}>
<Text>{comment.message}</Text>
<Button
title={`Go to ${comment.commenter}'s Profile'`}
onPress={() =>
navigation.push('Profile', { userId: comment.commenter })
}
/>
</View>
);
})}
</View>
);
};
// The screen you use to navigate to the profile screen
const InitialScreen = ({ navigation }) => {
return (
<View>
<Text>{`InitialScreen`}</Text>
<Button
title="Go to profile 1"
onPress={() =>
navigation.navigate('Profile', {
userId: 1,
})
}
/>
</View>
);
};
const ExampleNavigator = createStackNavigator({
Profile: { screen: ProfileScreen },
Comment: { screen: CommentScreen },
});
const MainNavigator = createStackNavigator(
{
SomeInitialScreen: { screen: InitialScreen },
ExampleNavigator: { screen: ExampleNavigator },
},
{
headerMode: 'none',
}
);
export default createAppContainer(MainNavigator);
Итак, идея здесь в том, что у вас есть массив, который содержит данные ваших пользователей, где каждый пользователь идентифицируется по идентификатору, userId
в этом примере. У пользователя также может быть comments
свойство, которое содержит message
от комментатора и идентификатор комментатора, commenter
.
Что касается навигации, единственное, что нам действительно нужно сделать, если у нас есть доступ к этим данным, чтобы реализовать такую структуру, — это передать userId
при переходе на страницу профиля и при переходе на страницу комментариев.
Я добавил MainNavigator
в этом примере, потому что из вопроса я предположил, что вы начинаете с другого экрана, например, с домашнего экрана, прежде чем перейти к профилю конкретного пользователя.
Обновить
OP указал, что ошибка с дублированием экрана была устранена путем отключения кнопок навигации после их нажатия. Это определенно простой и хороший способ сделать это, но поскольку это может быть кому-то полезно, я также объясню, как вы могли бы предотвратить дублирование в состоянии навигации.
Дублирование в данном случае означает, что мы уже видели определенный маршрут и userId
комбинацию. Я создал функцию, которая заменяет вызовы push в предыдущем примере:
function navigateByPushWithoutDuplicates(routeName, userId, navigation) {
const screenNavigatedToBefore = navigation
.dangerouslyGetParent()
.state.routes.find(
(element) =>
element.params.userId === userId amp;amp; element.routeName === routeName
);
if (screenNavigatedToBefore !== undefined) {
const navigateAction = NavigationActions.navigate({
routeName: routeName,
params: { userId: userId },
key: screenNavigatedToBefore.key,
});
navigation.dispatch(navigateAction);
} else {
navigation.push(routeName, { userId: userId });
}
}
С помощью этой функции вы могли бы сделать что-то вроде этого:
navigateByPushWithoutDuplicates("Comment", userId, navigation);
и это:
navigateByPushWithoutDuplicates("Profile", comment.commenter, navigation);
Комментарии:
1. Спасибо за ваш ответ, но navigation.navigate(‘Profile’, { userId: comment.commenter }) возвращает меня к экрану профиля вместо того, чтобы отправлять меня на новый экран профиля
2. Что вы имеете в виду, когда говорите «новый» экран профиля? Он переходит к тому же компоненту, но содержимое изменилось, это важная часть, верно?
3. Я думаю, я понимаю, что вы имеете в виду, вы можете использовать
push
вместоnavigate
. Я обновил код в своем ответе. Затем он сохраняет историю того, где вы были.4. Я думаю, что нашел исправление для этого, но это довольно сложно. Итак, в основном вам нужно отслеживать текущее состояние навигации
ExampleNavigator
и проверять, есть ли у вас уже маршрут в состоянии с определенной комбинациейrouteName
иuserId
. Если вы уже это сделали, вы вернетесь к первой комбинации, которую вы нашли по ее ключу.5. Спасибо, но я исправил проблему, разрешив пользователю нажимать кнопку только один раз. Вы мне очень помогли!