akveo / react-native-ui-kitten

:boom: React Native UI Library based on Eva Design System :new_moon_with_face::sparkles:Dark Mode
https://akveo.github.io/react-native-ui-kitten/
MIT License
10.32k stars 953 forks source link

Component inside Tab won't re-render when a prop changes its value. #505

Closed NBoychev closed 5 years ago

NBoychev commented 5 years ago

Issue type

I'm submitting a ...

Issue description

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.

Other information:

OS, device, package version

OS: iOS 12
Device: iPhone Xs
Package version: 4.0.5
32penkin commented 5 years ago

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:

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 {

static navigationOptions: NavigationScreenConfig = ({ 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}
  />
);

} }

2. Component:

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) => ({}));


3. Inner Component:

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 {

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) => ({}));

NBoychev commented 5 years ago

@32penkin I've simplified the case and created a snack so you can check the problem: Screen Recording 2019-07-09 at 03 56 PM

Snack link: https://snack.expo.io/@nboychev/kitten-tab-content-change

NBoychev commented 5 years ago

@32penkin @artyorsh , let's reopen the issue?

artyorsh commented 5 years ago

@NBoychev yes, sure. I will deal with this today

artyorsh commented 5 years ago

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 :)

32penkin commented 5 years ago

@NBoychev sorry for the misunderstanding. I just used the "master" version of the framework, so everything worked for me :)

NBoychev commented 5 years ago

Thanks! I was just testing this on your playground and it worked.

Keep up the great work!

artyorsh commented 5 years ago

@NBoychev You can update to the latest 4.1 version 🎉 Thanks for supporting us!

linhtc commented 5 years ago

How about if I use ver 3.1.4?