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

Consider renaming initialPage #126

Closed
grabbou opened this issue Jan 13, 2016 · 22 comments
Closed

Consider renaming initialPage #126

grabbou opened this issue Jan 13, 2016 · 22 comments

Comments

@grabbou
Copy link

grabbou commented Jan 13, 2016

It's actually currentPage since it reacts to changes https://github.com/brentvatne/react-native-scrollable-tab-view/blob/master/index.js#L55 (or maybe at least clarify that in docs?)

@skv-headless
Copy link
Collaborator

absolutely agree

@grabbou
Copy link
Author

grabbou commented Jan 13, 2016

It depends on expected by user behaviour, we can either:

  • revert old initialPage behaviour & implement page prop
  • clarify that in docs, make page prop and log that initialPage is deprecated and will be removed with next version

@skv-headless
Copy link
Collaborator

First option is better for me.

@skv-headless
Copy link
Collaborator

related issues #137 , #135 ,#128 ,#129

@robtg4
Copy link

robtg4 commented Feb 4, 2016

So what was the conclusion here - how can this problem of popping back to the initial set page be solved?

@digital-flowers
Copy link

@robtg4 i think it's not the component job to do so it's the user implementation to decide the initial state using redux or what ever he wants

@eseQ
Copy link

eseQ commented May 25, 2017

UPDATE 2 - solution
I returned to this problem again and found simple solution.
For control with Redux we don`t need use page - we need goToPage (how could i miss it before?)

UPDATE

All of i wrote next will work only for controlled tabs with Redux, but i catch scroll back if just swipe to other tab (if change with Redux or tap on TabBar all work fine).
But for control with Redux next solution work well.


TL;DR
Add identical initialPage and page on start, don`t change initialPage, change only page;
Update don`t use page - only initialPage on start and goToPage for change page.

I use redux for save my current tab (I change it in other place).
I want change active tab in drawer if that route active or initial specific tab if go from other route.

constructor() {
  super();
  this.pageProps = {} // can declare just in class
  this.pageIndex = null // ** Update **
}

Ok we have object for save component`s page data;
!important; keep it in mind! For initial Tabs we need set identical initialPage and page (use goToPage, if use page u can catch slide back). But for change tab we don`t need change initialPage. If we change initialPage without unmount component or set different values - tabs jump out of range and tab will not be loaded -_-

handleChangeScreen = ({ i }) => {
  this.pageIndex = i; // **Update ** save current page index
  this.props.dispatch(setMainScreen(i));
}

just handle onChangeTab and set in Redux (mainScreen - name of var for current tab in Redux)
Next step:

if (!this.pageProps.initialPage) this.pageProps.initialPage = mainScreen;

mainScreen - index current tab. Don`t change initialPage if tabs already init.


if (!this.pageProps.page || !this.pageProps.page !== mainScreen) this.pageProps.page = mainScreen;

Set page for init or change if page changed in Redux. Don`t use this code

Update
Now we need catch receive new mainScreen if it change outside

componentWillReceiveProps(nextProps) {
  const { YouStore: { mainScreen } } = nextProps;
  if ( this.props.YouStore.mainScreen !== mainScreen && mainScreen !== this.pageIndex) {
    if (this.tabView) this.tabView.goToPage(mainScreen)
  }
}

<ScrollableTabView
  {...this.pageProps}
  onChangeTab={this.handleChangeScreen}
  ref={(tabView) => { this.tabView = tabView; }} // set tabView
  ...
/>

Add props to ScrollableTabView. Have fun.

I try explain in detail, perhaps i can`t did it =).

@digital-flowers
Copy link

i think many components has an issue with interacting with redux the main reason is sometime you need redux to control the component and sometime you need the component to control redux maybe all components should consider doing the following scenario:

  • from user interaction (e.g click, slide)
    ==run==> internal event handler (this.onClick)
  • from internal handler
    ==if external handler exits ==> run (this.props.onClick)
  • after external handler call
    == if return true ==> change internal state (this.setState({page}))
    == if return false ==> do nothing
  • listen for props (e.g componentWillReceiveProps)
    == if prop not equal state ==> change internal state (this.setState({page:this.props.page}))

@digital-flowers
Copy link

in this way you can listen to the event cancel it and change your redux state in the other hand redux will change your component prop again :)

@eseQ
Copy link

eseQ commented May 26, 2017

@digital-flowers yeah, i agree, that will be awesome. If we don`t control component - just do u job, but if we do - doesn`t disturb =)

@digital-flowers
Copy link

exactly !

@eseQ
Copy link

eseQ commented Jun 1, 2017

UPDATE
I returned to this problem again and found simple solution.
For control with Redux we don`t need use page - we need goToPage (how could i miss it before?)
I updated my past solution.

Sorry for long read

@Froelund
Copy link

Froelund commented Jun 6, 2017

@dictory Could you elaborate how you would use goToPage in a redux setup? I can't really figure out what you mean is your solution in the previous comment with all those updates :)

@eseQ
Copy link

eseQ commented Jun 7, 2017

@Froelund, my post with update actual now(doesn't content old code).
That work for me on iOS. Have no idea about android - test it )
Save actual page index (or name if you want) to Redux store. Two point:

  1. In component with tabs:
handleChangeScreen = () => {
  this.pageIndex = i; // save local too
  this.props.dispatch(saveCurrentTabToRedux(i));
}
...
<ScrollableTabView
  ...
  onChangeTab={this.handleChangeScreen}
>
  1. Change page outside (for example):
this.props.dispatch(saveCurrentTabToRedux(2));

Next. Add ref to ScrollableTabView

<ScrollableTabView
  ...
  ref={(tabView) => { this.tabView = tabView; }}
>

Detect page change outside:

componentWillReceiveProps(nextProps) {
  const { YouStore: { pageIndex } } = nextProps;
  if ( this.props.YouStore.mainScreen !== pageIndex && pageIndex !== this.pageIndex) {
    if (this.tabView) this.tabView.goToPage(pageIndex)
  }
}

You are awesome. Don`t forget set initialPage.

@Angelk90
Copy link

@dictory :
Hi, I did as you say.
But I realized that by using, onChangeTab, I undergo some slowdowns, then the parameter that returns the function is an Obj not an int.

@grabbou , @digital-flowers : So I ask is there a way to know index of the tab that is selected in every moment, how can I do, I do not know using its reference by chance?

@fqr1
Copy link

fqr1 commented Apr 11, 2018

@dictory
It worked like a charm

Just one thing, in this section:

handleChangeScreen = () => { this.pageIndex = i; // save local too this.props.dispatch(saveCurrentTabToRedux(i)); }

the variable "i" is not mentioned where it comes from, should be

handleChangeScreen = ({i}) => { this.pageIndex = i; // save local too this.props.dispatch(saveCurrentTabToRedux(i)); }

@digital-flowers
Copy link

in @dictory example instead of using the local variable this.pageIndex you can just use this.tabView.state.currentPage

@khat33b
Copy link

khat33b commented Sep 27, 2018

@dictory I am finding it hard to understand your instructions. Can you please provide an Expo snack for this?

@eseQ
Copy link

eseQ commented Oct 9, 2018

@khat33b sorry, I stoped use this library in my projects.

@newCaoTao
Copy link

@eseQ , what library do you use now? could you share with me? thanks

@eseQ
Copy link

eseQ commented Feb 6, 2020

@newCaoTao, @khat33b last year I work on non react-native project.
But I find this:

class MainScreen extends React.Component {
  tabView = null;
  loadCount = 0;
  screenKey = null;
  initialPage = null;
  screens = [
    {
      key      : 'tags',
      component: () => <TagsListAll key="tags" tabLabel="#" />,
    },
    ...
  ]
  componentWillReceiveProps(nextProps) {
    // mainScreen from store
    const { mainScreen } = nextProps;
    if (
      this.props.mainScreen !== mainScreen && mainScreen !== this.screenKey &&
      this.loadCount > 2 && this.screenKey !== null && !!this.tabView
    ) this.tabView.goToPage(this.getScreenIndex(nextProps));
  }
  getScreenIndex = (props = this.props) => findIndex(this.screens, ['key', props.mainScreen]);
  renderTabBar = () => (
    <ScrollableTabBar
      style={styles.tabBar}
      tabsContainerStyle={styles.tabsContainer}
      tabStyle={styles.tab}
    />
  )
  handleChangeScreen = ({ i }) => {
    this.screenKey = (this.screens[i] && this.screens[i].key) || (this.otherPosts[i] && this.otherPosts[i].key);
    this.props.dispatch(setMainScreen(this.screenKey));
  }
  getList = list => map(list, screen => screen.component({ settings: this.props.Settings }))
  render() {
    const { mainScreen } = this.props;
    const screens = this.getList(this.screens.concat(this.otherPosts));
    this.loadCount += 1; // hook strange bug
    if (this.initialPage === null) {
      const screenIndex = this.getScreenIndex();
      this.screenKey = mainScreen;
      this.initialPage = screenIndex;
    }
    return (
      <ScrollableTabView
        initialPage={this.initialPage}
        onChangeTab={this.handleChangeScreen}
        renderTabBar={this.renderTabBar}
        ref={(tabView) => { this.tabView = tabView; }}
        ...
      >
        {screens}
      </ScrollableTabView>
    );
  }
}

export default MainScreen;

I recommend use functional component and useEffect instead componentWillReceiveProps.

@eramudeep
Copy link

componentWillReceiveProps

having trouble with the StateLess component.
when the onChangeTab trigger. it re-redner the component twice .
not sure why

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

No branches or pull requests