Skip to content
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

add withNavigationFocus HOC #3512

Merged
merged 10 commits into from
Feb 17, 2018
Merged

Conversation

slorber
Copy link
Member

@slorber slorber commented Feb 13, 2018

As discussed in other issues, we should be able to know easily which screen has the focus.

This HOC idea has been mentioned here by @satya164 and @ericvicenti

Here is a basic implementation using the new lifecycle hooks to provide this feature

@codecov-io
Copy link

codecov-io commented Feb 13, 2018

Codecov Report

Merging #3512 into master will decrease coverage by 0.54%.
The diff coverage is 0%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3512      +/-   ##
==========================================
- Coverage    72.6%   72.05%   -0.55%     
==========================================
  Files          51       52       +1     
  Lines        1595     1607      +12     
==========================================
  Hits         1158     1158              
- Misses        437      449      +12
Impacted Files Coverage Δ
src/views/withNavigationFocus.js 0% <0%> (ø)
src/react-navigation.web.js 0% <0%> (ø) ⬆️
src/react-navigation.js 0% <0%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 69bca19...674389a. Read the comment docs.

@slorber
Copy link
Member Author

slorber commented Feb 13, 2018

just added an example to playground app: TabsWithNavigationFocus

Copy link
Contributor

@ericvicenti ericvicenti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is exactly what I had in mind. Thanks for the contribution!!

};

componentDidMount() {
if (this.props.navigation) {

This comment was marked as abuse.

),
];
} else {
console.warn(

This comment was marked as abuse.

<Component
{...this.props}
isFocused={this.state.isFocused}
ref={this.props.onRef}

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

@slorber
Copy link
Member Author

slorber commented Feb 13, 2018

I updated the PR to get navigation from both props and context

@ericvicenti
Copy link
Contributor

Oh yay, flow errors! 😭

Error: js/TabsWithNavigationFocus.js:7
  7: import { TabNavigator, withNavigationFocus } from 'react-navigation';
                            ^^^^^^^^^^^^^^^^^^^ Named import from module `react-navigation`. This module has no named export called `withNavigationFocus`.

Error: js/TabsWithNavigationFocus.js:21
 21:       <SampleText>Tab {name}</SampleText>
           ^^^^^^^^^^^^ React children array. Could not decide which case to select
 12: const SampleText = ({ children }: { children?: ChildrenArray<*> }) => (
                                                    ^^^^^^^^^^^^^^^^ union type. See: js/SampleText.js:12
  Case 1 may work:
  223:   declare export type ChildrenArray<+T> = $ReadOnlyArray<ChildrenArray<T>> | T;
                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ read-only array type. See lib: /tmp/flow/flowlib_28386f1e/react.js:223
  But if it doesn't, case 2 looks promising too:
   12: const SampleText = ({ children }: { children?: ChildrenArray<*> }) => (
                                                                    ^ existential. See: js/SampleText.js:12
  Please provide additional annotation(s) to determine whether case 1 works (or consider merging it with case 2):
   21:       <SampleText>Tab {name}</SampleText>
                              ^^^^ name


Found 2 errors
error Command failed with exit code 2.
Exited with code 1

Looks like you need to add a definition for this new HOC in flow/react-navigation.js

@ericvicenti
Copy link
Contributor

As for the getWrappedInstance vs props.onRef question, lets move that to a follow-up issue/PR/RFC, because we're already invested in props.onRef for now because of withNavigation. I don't have a strong preference either way, so I'll leave it up to y'all, but I believe that onRef requires a tiny bit less boilerplate for people.

@slorber
Copy link
Member Author

slorber commented Feb 14, 2018

fixed the flow errors on playground, tell me if there's anything else to do

@brentvatne brentvatne merged commit c74f001 into react-navigation:master Feb 17, 2018
@brentvatne
Copy link
Member

@slorber - can you open a PR on the website repo with an API reference for this? http://github.com/react-navigation/website

@brentvatne
Copy link
Member

brentvatne commented Feb 17, 2018

@slorber - it turns out that this isn't a reliable way to find the navigation focused state. it will only work if it is wrapping a navigation screen. if you add it to some component in the screen, and that component is rendered after the parent screen component is mounted, this will not work until you navigate to and away from the screen where it's rendered. this is because it depends on navigation events, and those are only fired when things change. we need some way to be able to reach in to the parent navigation state and determine if it is focused synchronously on mount, in the state initializer. cc @ericvicenti

@satya164
Copy link
Member

Maybe a this.props.navigation.isFocused() method will be helpful to get the current focused state? Users can get the initial focus state by using it in componentWillMount

@slorber
Copy link
Member Author

slorber commented Feb 17, 2018

I understand that problem, do you have any solution to propose?

What about a new navigator config withNavigationFocus: true, and making the HOC private/lib internal. This way all screens will be wrapped by the HOC and we can be sure they won't be mounted after the focus event. This HOC makes mostly sense at the root so navigator config can be an appropriate place.

@satya164 I wouldn't use such isFocused function. I've used such child component querying parent from function prop and this get really confusing because if you use this on render (and be certain people will try that) you will be confused because the component won't render on focus change if the component is pure and function is stable. I tricked myself with that in the past.

@satya164
Copy link
Member

satya164 commented Feb 17, 2018

Another option is to always call the listener with the current value synchronously as soon as you attach it.

@slorber
Copy link
Member Author

slorber commented Feb 17, 2018

I like this idea (it's what History.listen does to provide immediate history location), but shouldn't we create a onFocusChange or something instead of calling didFocus immediately?

@brentvatne
Copy link
Member

brentvatne commented Feb 23, 2018

I don't like calling didFocus immediately, this leads to IMO some confusing behaviors. I also don't like calling onFocusChange to solve the problem that I mentioned above because it's semantically incorrect. We should just expose isFocused(), and initialize the withNavigationFocus state from that.

};

state = {
isFocused: false,

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

sourcecode911 pushed a commit to sourcecode911/react-navigation that referenced this pull request Mar 9, 2020
* add withNavigationFocus HOC

See:
- react-navigation#51 (comment)
- react-navigation#51 (comment)
- react-navigation#3345 (comment)

* typos

* remove unused import

* Add withNavigationFocus export

* add example TabsWithNavigationFocus

* add example TabsWithNavigationFocus

* withNavigationFocus: get navigation from context or props

* subs => subscriptions

* fix flow issues
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants