0

Using React-Navigation, I am trying to generate an unknown number of tabs based off of the values that I've drawn from an array, and pass the data from that array value into the screen. For example, if I have 2 accounts, I would expect 2 tabs with screens for each one, but if I have 5 accounts, there are 5 tabs, with their own screens that are generated programatically from the values that are sent across from the database.

What I have so far, and what I am trying to do is:

interface Account {
    accountNumber: string;
    balance: number;
}

const accounts: Account[] = [
    { accountNumber: '1', balance: 10 },
    { accountNumber: '2', balance: 15 },
    { accountNumber: '3', balance: 20 }
];


class AccountScreen extends React.Component<Account>{
    constructor(props: Account) {
      super(props)
    }

    render() {
        return (
          <View>
            <Text>This is an Account</Text>
            <Text>Account Number: {this.props.accountNumber}</Text>
            <Text>Balance: £{(this.props.balance/100).toFixed(2)}</Text>
          </View>
        );
    }
};

const accountScreens = {};

accounts.forEach(account => accountScreens[account.accountNumber] = { screen: AccountScreen, props: account }); 
// SOMETHING LIKE THIS

export default AccountNavigator = createMaterialTopTabNavigator(accountScreens);

The screens render with the correct tabs, but the values within each account are not passed down through props. I know that you can't pass pass props directly into the Navigator, but I cannot figure out how that data could be accessed by the component.

Am I building this fundamentally wrong, or is there just some syntactic thing that I'm missing?

Thanks for your help!


Solution

I didn't realise that the props could be accessed with a returning function to the screen key in the navigator.

Below is the final solution that worked for me:

accounts.forEach(account => {
    accountScreens[account.accountNumber] = {screen: (props) => {
        return <AccountScreen accountNumber={account.accountNumber} {...props} />}
    }
})

2 Answers2

0

P.S I did not check it but it is how you do it!

/*...your code*/

let screens = accounts.map(e=>{screen:(props)=><AccountScreen account={e} {...props}/>})

export default AccountNavigator = createMaterialTopTabNavigator({...screens});

Note: After this code your screen names will indexes of your objects. When you would like to navigate you should use navigation.navigate('1')

You are trying to generate screens on initialization it is totally ok. But I would recommend you to use just one screen and tweak with the values there!

OriHero
  • 1,168
  • 1
  • 10
  • 24
  • This is exactly the solution to the problem. I didn't know that the screen key in the createXNavigator had access to the props in it's parameters. Thanks! – Bev Rivling Dec 02 '19 at 10:20
0

The current stable version of React Navigation doesn't support dynamically generating screens based on some data.

React Navigation 5 has a new dynamic API which makes it possible: https://blog.expo.io/announcing-react-navigation-5-0-bd9e5d45569e

satya164
  • 9,464
  • 2
  • 31
  • 42
  • Appreciate the feedback and RN v5 looks great, but I was able to achieve this goal with Abdumutal Abdusamatov's answer. – Bev Rivling Dec 02 '19 at 10:26