Skip to content
This repository has been archived by the owner on Feb 15, 2019. It is now read-only.

isFocused is not set correctly when Scene is rendered as initialRoute on StackNavigation #107

Open
ptomasroos opened this issue Sep 21, 2016 · 13 comments

Comments

@ptomasroos
Copy link
Contributor

ptomasroos commented Sep 21, 2016

No description provided.

@ptomasroos
Copy link
Contributor Author

ptomasroos commented Sep 21, 2016

I tried getting something running by looking at the AndroidBackButtonBehaviour.

Since all Components through _makeRoute are focusAwareComponents.

I added following

  componentDidMount() {
    Alert.alert(' yup ' + this.props.isFocused);

    if (this.props.isFocused) {
      Alert.alert('Is focused');
    }
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.isFocused && !this.props.isFocused) { // becomes focused
      Alert.alert('Is focused');
    } else if (!nextProps.isFocused && this.props.isFocused) { // becomes unfocused
      Alert.alert('Unfocused');
    }
  }

But on the first initialRoute in the Tab + StackNavigation in componentDidMount isFocused is false.
And will never recieve new props.

Pusing a route, does not yield a unfocused either.

BUT!

Poping back to initialRoute now causes isFocused.
And leaving with a push causes Unfocused.

I'm clearly missing something on the first render.

@ptomasroos ptomasroos changed the title onFocus / onBlur for routes. isFocused is not set correctly when rendered as initialRoute on StackNavigation Sep 28, 2016
@ptomasroos ptomasroos changed the title isFocused is not set correctly when rendered as initialRoute on StackNavigation isFocused is not set correctly when Scene is rendered as initialRoute on StackNavigation Sep 28, 2016
@ptomasroos
Copy link
Contributor Author

Sure thing! Already debugged that code to find out a part of the problem.

The problem is that the event handler is subscribed after the scene is already mounted / rendered.
And hence never receiving it.

@ptomasroos
Copy link
Contributor Author

ptomasroos commented Oct 5, 2016

@skevy truly sorry for delaying the output when requesting your attention
I get nil.

So i created a example app demonstrating it for you.

https://github.com/ptomasroos/minimalex

react-native run-ios

Notice that the first tab rendering has isFocused false.
If you click the third profile, then home again.
Now it says yes, bceause the subscriber probably reacts in the mounted component at this stage.

If you go to the stack on profile and click the "This works to push, click me"
You can see that a pushed scene does not get isFocused true either, its false. Same type of error.

When a Component is rendered there is no way for it to be able to get isFocused true.

@skevy
Copy link
Contributor

skevy commented Oct 5, 2016

Thanks for the repro case @ptomasroos. This is super helpful.

I'm 90% sure I know what's going on, and I think it's a fundamental flaw in the isFocused implementation.

Gonna think through this a bit now.

@chirag04
Copy link
Contributor

chirag04 commented Oct 5, 2016

while you think about it, it's worth thinking about how we can avoid that extra re-render those who don't care about isFocused. we discussed about pull model instead of push based.

I suggest isFocused as a function :)

@ptomasroos
Copy link
Contributor Author

You're welcome @skevy

That could def be the case @chirag04

But I think a concept of rather onEnter / onExit as es6 class methods on the given Component would work good as well.

Should remember that is too few life cycle hooks when it comes to app since much stuff is mounted almost forever :)

Then one can decide to set the state if its needed for rendering or just call for Analytics screen tracking view or logging.

@chirag04
Copy link
Contributor

chirag04 commented Oct 5, 2016

or just let the user do createFocusableComponent instead of having that as default. idk

https://github.com/exponentjs/ex-navigation/blob/79a7a5b87007bffe35b0947ac23996b20be9d6e1/src/ExNavigationComponents.js#L145

@chirag04
Copy link
Contributor

chirag04 commented Oct 5, 2016

i can imagine having to do createFocusableComponent in every screen component will be PITA. maybe have some prop on <StackNavigation> that enable/disables the default behavior.

@lprhodes
Copy link

My work-around for this was to create my own component wrapper which is then subclassed by each top-level view component that needs to know whether it's focused or not.

The wrapper has an onFocusChange method which is called whenever the component is rendered using the following
ref={() => this.onFocusChange({ focused: true})}

this._isFocused is set so that we make sure we only call focus or unfocus code when it's changed and not for repeat events.

Whenever a component is focused, an event emitter is used to let other components know that they are now unfocused so they can do anything they need to.

@annelorraineuy
Copy link

@lprhodes Would you mind sharing an example of your workaround? I am not sure where the wrapper should be given the stacknavigation syntax my redux store provider.

@alexprice1
Copy link

Yeah, any help here would be really appreciated!

@lprhodes
Copy link

lprhodes commented Apr 6, 2017

Unfortunately I found too many issues and had to stop using onFocus type code sorry.

I ended up defining callback methods and using event emitters to call them from views I'd pushed so I could perform an a top on the parent view when I did something in a child view.

This got me most of the way.

I'll be moving to https://reactnavigation.org asap

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants