-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pass function callback as props to scenes #322
Comments
Hey, great to hear from you again. You can't pass functions in navigation data. If you let me know your use-case then I'll try and help out |
The navigation library(react-native-navigation) we used before can pass function call to its "screens". I am planning to build a feature similar to this one for backward compatibility. |
Let me see if I understand what you're trying to do. If you navigate from A --> B --> C then you want to update B's navigation data when you're on C. Is that right? |
Yes, do you have any advice for this scenario? |
Yes, you can do that using fluent navigation. Let's say that when you first navigated from A to B you passed 'x' with a value of 1 in navigation data // On Scene A
stateNavigator.navigate('B', {x: 1}); Now, you're on C and you want to change the 'x' navigation data to 3 on scene B. // On Scene C
var link = stateNavigator.fluent(true)
.navigateBack(2)
.navigate('B', {x: 3})
.navigate('C').url;
stateNavigator.navigateLink(url|); You see, fluent navigation lets you perform multiple navigations at once. Here we're navigating back 2 scenes to A, then navigating forward to B and passing the new value for x, then navigating forward to C again. The Navigation router only applies these navigations when you call |
Sorry, I made a mistake in the fluent navigation code sample. I've corrected it, so please give it a reread |
Seems promising, but still not flexible enough compared to passing callback. Consider this scenario: In scene B, user click a button navigating to scene C. If scene C is displaying a dialog which contains two button for user to click(cancel/confirm). After user clicks one of them, we do as following: // On Scene C
var link = stateNavigator.fluent(true)
.navigateBack(2)
.navigate('B', {clickedButtonIndex: 0});
stateNavigator.navigateLink(url|); And user navigateBack to scene B now. Then user click another button navigating to scene D, which is the same component as scene C. If user clicks cancel/confirm button in scene D, then we have to figure out where is this click event from (try not to mess up with scene C). |
I'm confused. Can you explain what you can do with the callback that you don't think you can do with fluent navigation, please? |
Sorry, since I am not a native english speaker, it's hard to make myself clear. |
I wouldn't use fluent navigation to tell screen B that you clicked a button on screen C. You should only use fluent navigation to change navigation data. If you want to tell screen B that you clicked a button then you should use React context. React context is the way to communicate and pass data between scenes. |
Understood. Thanks for your explaining. |
No problem. Thanks for the question. You couldn't use React Context with react-native-navigation because each scene is mounted under a different React root element. You can use React Context with the Navigation router because all scenes share a common React root element. |
IMO, being able to pass function as data helps to increase flexibility. Consider a selectable user list scene, which may be used in many places in an app. stateNavigator.navigate('users-selector', {
title: "Contacts",
fetchData: () => {
// Fetch from contacts
},
renderListItem: (user) => {
// Render a contact list item
},
onSelected: (users) => {
}
})
// Another place:
stateNavigator.navigate('users-selector', {
title: "Team Members",
fetchData: () => {
// Fetch from team members
},
renderListItem: (user) => {
// Render a member list item
},
onSelected: (users) => {
}
}) The 'users-selector' scene handles selection state management, template header & bottom components rendering and so on. By passing custom action as function through data, we can make |
Hey @studyroz It's better to do things like that with React than with the Navigation router. For example, you can wrap the |
@grahammendick I disagree. Its a really simple pattern that is way clearer than having to wrap everything in a context/ HOC. I'm not talking about the callbacks for fetching data but moreso the ones @studyroz defined for I would argue that this hurts reusability too because as I understand it you cant have props that are callbacks when using a screen? So when designing you have to change the way you would normally write something to conform to the limitations of the Navigation functionality |
@mpiannucci Sounds like you’re looking for a convenient way to pass data back from Scene B to Scene A, right? I’ll try and explain why I don’t think that’s a good idea. I’ll use Hooks because it makes the problem more obvious. Here’s Scene A. It displays a count and has a button that navigates to Scene B. When it navigates to Scene B it passes a callback that adds 1 to the count. const SceneA = () => {
const {count, setCount} = useState(0)
const {stateNavigator} = useContext(NavigationContext);
const add = () => setCount(count + 1)
return (
<>
<Text>{count}</Text>
<Button onPress={() => stateNavigator.navigate('sceneB', { add }) />
</>
)
} Let’s say that Scene B calls the |
Aha good call. Thanks for the explanation. Some of this is new to me coming from c++ and swift where the flow is a little different |
So I am hitting this again. I am trying to display a modal screen where a user can select an item, the modal is dismissed, and then that item is presented in the main view. I forgot this wasn't possible and was going crazy trying to figure out why the callback wasn't working. Is there any technical limitation to why passing callbacks isn't supported? I know the case with setting the count and such but my flow deals with strings so i am strictly trying to present a one off select and then closing the dialog. I want the native search bar functionality, otherwise i wouldn't give the modal its own navigation context. I am aware I can use context to manage this state but it would be a lot cleaner not to. |
You don’t have to use context. You can pass the function as a prop. const [val, setVal] = useState(null);
const modalNavigator = useMemo(() => {
const navigator = new StateNavigator([
{key: ‘search’}
]);
const {search} = navigator.states;
search.renderScene = () => <Search setVal={setVal} />
navigator.navigate('search');
return navigator;
}, [setVal]);
return (
<Modal>
<NavigationHandler stateNavigator={modalNavigator}>
<NavigationStack />
</NavigationHandler>
</Modal>
); |
So you can pass a function as long as you pass it to render scene. Great thanks for the help!!!!! |
Here’s a more complete example of how you can use props, instead of context, to pass data from a parent scene to a modal scene (make sure you’re using the just published const Wrapper = ({state, ...props}) => state.renderScene(props);
const ParentScene = () => {
const [val, setVal] = useState();
const modalNavigator = useMemo(() => {
const navigator = new StateNavigator([{key: 'scene'}])
const {scene} = stateNavigator.states;
scene.renderScene = (props) => <ModalScene {...props} />;
navigator.navigate('scene');
return navigator;
}, []);
return (
<NavigationHandler stateNavigator={modalNavigator}>
<NavigationStack renderScene={(state) => (
<Wrapper state={state} val={val} setVal={setVal} />
)} />
</NavigationHandler>
);
} |
Hello, it's me again.
One question, how do we pass function type props to scenes?
I am doing something like this:
However, the value for
callback
insceneB.renderScene
is undefined.It seems function type variable is erased from
navigationData
when encoding data to routeInfo and decoding it back from routeInfo?The text was updated successfully, but these errors were encountered: