我是原生反应新手,正在尝试使用
expo-router
在模式标题中连接一个保存按钮。我可以让按钮在模式本身中执行我需要的操作,但我希望它位于从 expo-router 设置的标题中。将数据保存逻辑移至路由文件中似乎并不正确,即使我这样做,我也会收到这些领域上下文错误。所以我不知道如何继续。有没有办法通过世博会满足我的需要?在我看来,这个用例应该很常见,但我似乎在任何地方都找不到示例,包括他们的文档。
_layout.tsx
import React from 'react';
import { RealmProvider } from '@realm/react';
import { router, Stack } from 'expo-router';
import { HeaderButton } from '@components/common/fields/HeaderButton';
import { schemas } from '@models/index';
export default function Layout() {
return (
<RealmProvider schema={schemas} deleteRealmIfMigrationNeeded={true}>
<Stack>
<Stack.Screen
name="index"
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="modal"
options={{
presentation: 'modal',
headerTitle: () => (
<HeaderButton displayText="<" handleClick={() => router.back()} />
),
// headerRight: () => (
// <HeaderButton
// handleClick={}
// displayText="Save"
// />
// ),
}}
/>
</Stack>
</RealmProvider>
);
}
modal.tsx
import React from 'react';
import { StatusBar } from 'expo-status-bar';
import { View } from 'react-native';
import { AddRecipeForm } from '@screens/recipe/AddRecipeForm';
export default function Modal() {
return (
<View>
<StatusBar style="light" />
<AddRecipeForm />
</View>
);
}
添加RecipeForm.tsx
import React, { useCallback } from 'react';
import { useRealm } from '@realm/react';
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
import { StyleSheet, View } from 'react-native';
import { HeaderButton } from '@components/common/fields/HeaderButton';
import { TextField } from '@components/common/fields/TextField';
import { Recipe } from '@models/Recipe';
import colors from '@styles/colors';
interface AddRecipeFormProps {
userId?: string;
}
interface FormData {
userId?: string;
description: string;
name: string;
}
export const AddRecipeForm: React.FC<AddRecipeFormProps> = ({
// toggleModal,
userId,
}) => {
const { control, handleSubmit } = useForm<FormData>();
const realm = useRealm();
const handleAddRecipe = useCallback(
(name: string, description: string): void => {
if (!description && !name) {
return;
}
realm.write(() => {
return realm.create(Recipe, {
name,
description,
userId: userId ?? 'SYNC_DISABLED',
});
});
},
[realm, userId],
);
const onSubmit: SubmitHandler<FormData> = (data) => {
handleAddRecipe(data.name, data.description);
};
return (
<>
<View style={styles.container}>
<View style={styles.buttonContainer}>
<HeaderButton
displayText="Save"
handleClick={handleSubmit(onSubmit)}
/>
{/* <CustomButton displayText="Cancel" handleClick={toggleModal} /> */}
</View>
<Controller
control={control}
// rules={{ required: true }}
render={({ field: { onChange, value } }) => (
<TextField
value={value}
onChangeText={onChange}
placeholder="name"
/>
)}
name="name"
/>
<Controller
control={control}
// rules={{ required: true }}
render={({ field: { onChange, value } }) => (
<TextField
value={value}
onChangeText={onChange}
placeholder="description"
/>
)}
name="description"
/>
</View>
</>
);
};
tldr;更具体地说,我想移动
HeaderButton
及其所有功能,以在 _layout.tsx
堆栈中定义的模式标头中使用。将所有逻辑从组件移到布局中似乎并不合适(我也无法让它工作)。有办法实现吗?
我终于明白了。我实际上是通过阅读
expo-router
文档来计算出 react-navigation
的。 https://reactnavigation.org/docs/header-buttons/#header-interaction-with-its-screen-component
本质上,您在
_layout.tsx
中声明它,并使用 navigation.setOptions
在实际组件中“覆盖”它。请参阅下面两个文件中的 headerRight
道具。
_layout.tsx
export default function Layout() {
const router = useRouter();
return (
<RealmProvider schema={schemas} deleteRealmIfMigrationNeeded={true}>
<Stack>
<Stack.Screen
name="index"
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="modal"
options={{
presentation: 'modal',
headerTitle: 'Add Recipe',
headerLeft: () => (
<HeaderButton handleClick={() => router.back()} displayText="<" />
),
headerRight: () => <HeaderButton displayText="Save" />,
}}
/>
</Stack>
</RealmProvider>
);
}
添加RecipeForm.tsx
export const AddRecipeForm: React.FC<AddRecipeFormProps> = ({
// toggleModal,
userId,
}) => {
const { control, handleSubmit } = useForm<FormData>();
const realm = useRealm();
const navigation = useNavigation();
const router = useRouter();
const handleAddRecipe = useCallback(
(name: string, description: string): void => {
if (!description && !name) {
return;
}
realm.write(() => {
return realm.create(Recipe, {
name,
description,
userId: userId ?? 'SYNC_DISABLED',
});
});
},
[realm, userId],
);
useEffect(() => {
navigation.setOptions({
headerRight: () => (
<HeaderButton displayText="Save" handleClick={handleSubmit(onSubmit)} />
),
});
}, [navigation]);
const onSubmit: SubmitHandler<FormData> = (data) => {
handleAddRecipe(data.name, data.description);
router.back();
};
return (
<View style={styles.container}>
<Controller
control={control}
// rules={{ required: true }}
render={({ field: { onChange, value } }) => (
<TextField value={value} onChangeText={onChange} placeholder="name" />
)}
name="name"
/>
<Controller
control={control}
// rules={{ required: true }}
render={({ field: { onChange, value } }) => (
<TextField
value={value}
onChangeText={onChange}
placeholder="description"
/>
)}
name="description"
/>
</View>
);
};
希望这对某人有帮助,尤其是在
expo
文档如此稀疏的情况下。