I'm submitting a ...
Current behavior:
When a component prop inside <Tab /> is updated via the redux store, the component doesn't re-render.
Expected behavior:
The component should re-render when the prop changes.
Steps to reproduce:
Add component inside a <Tab />
Related code:
<TabView
selectedIndex={this.state.selectedIndex}
onSelect={this.handleTabSelect}
style={[styles.tabView]}
tabBarStyle={[styles.tabBarView]}
indicatorStyle={[styles.tabIndicator]}
>
<Tab title="Tab 1" titleStyle={[styles.tabTitle, this.state.selectedIndex === 0 && styles.tabTitleSelected]}>
...
</Tab>
<Tab title="Tab 2" titleStyle={[styles.tabTitle, this.state.selectedIndex === 1 && styles.tabTitleSelected]}>
...
</Tab>
<Tab title="Tab 3" titleStyle={[styles.tabTitle, this.state.selectedIndex === 2 && styles.tabTitleSelected]}>
...
</Tab>
<Tab title="Tab 4" titleStyle={[styles.tabTitle, this.state.selectedIndex === 3 && styles.tabTitleSelected]}>
<MyCustomComponent propFromRedux={propFromRedux} />
</Tab>
</TabView>
The MyCustomComponent won't re-render when propFromRedux change its value.
To make sure that the problem is not in MyCustomComponent, I've moved it outside the <TabView /> and when the propFromRedux changed, the component re-rendered.
OS, device, package version
OS: iOS 12
Device: iPhone Xs
Package version: 4.0.5
Hello @NBoychev ! Thanks for your report.
I've tested the issue and I believe that there is some mistake in your code.
Below you can check a similar working example:
GIF:

Code:
import React from 'react';
import {
NavigationScreenConfig,
NavigationScreenProps,
} from 'react-navigation';
import { connect } from 'react-redux';
import { TestComp } from './test.component';
import { TopNavigationElement } from '@src/core/navigation/options';
import {
OrderListHeader,
OrderListHeaderProps,
} from '@src/components/orders';
import { GlobalState } from '../../store';
import { setOrdersFilterCriteria } from '../../actions';
interface StateProps {
filterCriteria: string;
setOrdersFilterCriteria: (criteria: string) => void;
}
type ComponentProps = NavigationScreenProps & StateProps;
const mapStateToProps = (state: GlobalState) => ({
filterCriteria: state.orders.filterCriteria,
});
const mapDispatchToProps = (dispatch: Function) => ({
setOrdersFilterCriteria: (criteria: string) => dispatch(setOrdersFilterCriteria(criteria)),
});
@connect(mapStateToProps, mapDispatchToProps)
export class TestContainer extends React.Component<ComponentProps> {
static navigationOptions: NavigationScreenConfig<any> = ({ navigation, screenProps }) => {
const ordersHeaderConfig: OrderListHeaderProps = {
onBack: navigation.getParam('onBack'),
onMenuItemPress: navigation.getParam('onMenuItemPress'),
...navigation,
};
const renderHeader = (headerProps: NavigationScreenProps) => {
return (
<OrderListHeader
{...headerProps}
{...ordersHeaderConfig}
/>
);
};
return {
...navigation,
...screenProps,
header: (headerProps: NavigationScreenProps): TopNavigationElement => {
return renderHeader(headerProps);
},
};
};
public componentWillMount(): void {
this.setNavigationParams();
}
private setNavigationParams = (): void => {
this.props.navigation.setParams({
onBack: this.onBackPress,
onMenuItemPress: this.onSearchOptionSelect,
});
};
private onBackPress = (): void => {
this.props.navigation.goBack(null);
};
private onSearchOptionSelect = (option: string): void => {
this.props.setOrdersFilterCriteria(option);
};
public render(): React.ReactNode {
const { filterCriteria } = this.props;
return (
<TestComp
propFromRedux={filterCriteria}
/>
);
}
}
import React from 'react';
import {
ThemedComponentProps,
ThemeType,
withStyles,
} from '@kitten/theme';
import {
Tab,
TabView,
Text,
} from '@kitten/ui';
import { ReduxWaitingTest } from './reduxWaitingTest.component';
interface State {
selectedIndex: number;
}
interface ComponentProps {
propFromRedux: string;
}
export type TestComponentProps = ThemedComponentProps & ComponentProps;
class TestComponent extends React.Component<TestComponentProps, State> {
public state: State = {
selectedIndex: 0,
};
private handleTabSelect = (selectedIndex: number): void => {
this.setState({ selectedIndex });
};
public render(): React.ReactNode {
const { propFromRedux } = this.props;
return (
<TabView
selectedIndex={this.state.selectedIndex}
onSelect={this.handleTabSelect}>
<Tab title='Tab 1'>
<Text>Tab1</Text>
</Tab>
<Tab title='Tab 2'>
<Text>Tab2</Text>
</Tab>
<Tab title='Tab 3'>
<ReduxWaitingTest propFromRedux={propFromRedux}/>
</Tab>
</TabView>
);
}
}
export const TestComp = withStyles(TestComponent, (theme: ThemeType) => ({}));
import React from 'react';
import {
ThemedComponentProps,
ThemeType,
withStyles,
} from '@kitten/theme';
import { Text } from '@kitten/ui';
interface ComponentProps {
propFromRedux: string;
}
export type ReduxWaitingTestComponentProps = ThemedComponentProps & ComponentProps;
class ReduxWaitingTestComponent extends React.Component<ReduxWaitingTestComponentProps> {
public render(): React.ReactNode {
const { propFromRedux } = this.props;
const value: string = propFromRedux ? propFromRedux : 'Select option';
return (
<Text>{value}</Text>
);
}
}
export const ReduxWaitingTest = withStyles(ReduxWaitingTestComponent, (theme: ThemeType) => ({}));
@32penkin I've simplified the case and created a snack so you can check the problem:

Snack link: https://snack.expo.io/@nboychev/kitten-tab-content-change
@32penkin @artyorsh , let's reopen the issue?
@NBoychev yes, sure. I will deal with this today
We got this fixed in master. ViewPager was refactored to use Animated.View instead of ScrollView. Will be available in the next release. Stay tuned :)
@NBoychev sorry for the misunderstanding. I just used the "master" version of the framework, so everything worked for me :)
Thanks! I was just testing this on your playground and it worked.
Keep up the great work!
@NBoychev You can update to the latest 4.1 version 🎉 Thanks for supporting us!
How about if I use ver 3.1.4?
Most helpful comment
Thanks! I was just testing this on your playground and it worked.
Keep up the great work!