mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-03-06 22:39:41 +08:00
fix: NavigationEvents subscribe events on new nav state (#8920)
If the navigation prop changes, the NavigationEvents component was not subscribing to the new value. These changes fix this problem and add a test to verify that behavior.
This commit is contained in:
@@ -12,11 +12,28 @@ const EventNames = Object.keys(EventNameToPropName);
|
||||
|
||||
class NavigationEvents extends React.Component {
|
||||
componentDidMount() {
|
||||
this.subscriptions = {};
|
||||
|
||||
// We register all navigation listeners on mount to ensure listener stability across re-render
|
||||
// A former implementation was replacing (removing/adding) listeners on all update (if prop provided)
|
||||
// but there were issues (see https://github.com/react-navigation/react-navigation/issues/5058)
|
||||
this.subscribeAll();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.navigation !== prevProps.navigation) {
|
||||
this.removeAll();
|
||||
this.subscribeAll();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.removeAll();
|
||||
}
|
||||
|
||||
getPropListener = (eventName) => this.props[EventNameToPropName[eventName]];
|
||||
|
||||
subscribeAll() {
|
||||
this.subscriptions = {};
|
||||
|
||||
EventNames.forEach((eventName) => {
|
||||
this.subscriptions[eventName] = this.props.navigation.addListener(
|
||||
eventName,
|
||||
@@ -28,14 +45,12 @@ class NavigationEvents extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
removeAll() {
|
||||
EventNames.forEach((eventName) => {
|
||||
this.subscriptions[eventName].remove();
|
||||
});
|
||||
}
|
||||
|
||||
getPropListener = (eventName) => this.props[EventNameToPropName[eventName]];
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@ import NavigationContext from '../NavigationContext';
|
||||
|
||||
const createPropListener = () => jest.fn();
|
||||
|
||||
const EVENT_TO_PROP_NAME = {
|
||||
willFocus: 'onWillFocus',
|
||||
didFocus: 'onDidFocus',
|
||||
willBlur: 'onWillBlur',
|
||||
didBlur: 'onDidBlur',
|
||||
};
|
||||
|
||||
// An easy way to create the 4 listeners prop
|
||||
const createEventListenersProp = () => ({
|
||||
onWillFocus: createPropListener(),
|
||||
@@ -122,6 +129,39 @@ describe('NavigationEvents', () => {
|
||||
checkPropListenerIsCalled('didBlur', 'onDidBlur');
|
||||
});
|
||||
|
||||
it('wires props listeners to latest navigation updates', () => {
|
||||
const {
|
||||
navigation,
|
||||
NavigationListenersAPI,
|
||||
} = createTestNavigationAndHelpers();
|
||||
const {
|
||||
navigation: nextNavigation,
|
||||
NavigationListenersAPI: nextNavigationListenersAPI,
|
||||
} = createTestNavigationAndHelpers();
|
||||
|
||||
const eventListenerProps = createEventListenersProp();
|
||||
const component = renderer.create(
|
||||
<NavigationEvents navigation={navigation} {...eventListenerProps} />
|
||||
);
|
||||
|
||||
Object.entries(EVENT_TO_PROP_NAME).forEach(([eventName, propName]) => {
|
||||
expect(eventListenerProps[propName]).toHaveBeenCalledTimes(0);
|
||||
NavigationListenersAPI.call(eventName);
|
||||
expect(eventListenerProps[propName]).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
component.update(
|
||||
<NavigationEvents navigation={nextNavigation} {...eventListenerProps} />
|
||||
);
|
||||
|
||||
Object.entries(EVENT_TO_PROP_NAME).forEach(([eventName, propName]) => {
|
||||
NavigationListenersAPI.call(eventName);
|
||||
expect(eventListenerProps[propName]).toHaveBeenCalledTimes(1);
|
||||
nextNavigationListenersAPI.call(eventName);
|
||||
expect(eventListenerProps[propName]).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('wire latest props listener to navigation listeners on updates (support closure/arrow functions update)', () => {
|
||||
const {
|
||||
navigation,
|
||||
|
||||
Reference in New Issue
Block a user