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

Picker (android): Convert children to an array before accessing with a position #8153

Closed
wants to merge 4 commits into from

Conversation

justim
Copy link
Contributor

@justim justim commented Jun 16, 2016

When using the following component, this.props.children is not a flat array.

class Example extends Component {
    // ...

    render() {
        const values = ['1', '2'];

        return (
            <Picker
                value={this.state.value}
                onValueChange={this.onValueChange.bind(this)}
            >
                <Picker.Item
                    label="n/a"
                    value={null}
                />

                {values.map(value => {
                    return (
                        <Picker.Item
                            label={value}
                            value={value}
                        />
                    );
                })}
            </Picker>
        );
    }
}

The resulting this.props.children is:

[
    (child),
    [
        (child),
        (child),
    ],
];

Therefor you can't use this.props.children[2] to get the last item.

The Android version of the Picker does exactly this to get the value of the selected item to pass to the onValueChange prop.

This PR fixes that by normalising the children with React.Children.toArray.

- `this.props.children` is not always a flat array.
@ghost
Copy link

ghost commented Jun 16, 2016

By analyzing the blame information on this pull request, we identified @mkonicek and @spicyj to be potential reviewers.

@ghost
Copy link

ghost commented Jun 16, 2016

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla - and if you have received this in error or have any questions, please drop us a line at cla@fb.com. Thanks!

@ghost
Copy link

ghost commented Jun 16, 2016

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 16, 2016
@mkonicek
Copy link
Contributor

The example seems reasonable but doing this the conversion in every change event seems unnecessary - the children don't change.

Is it possible to do the conversion just once? Alternatively, could you create a flat list in your application code?

[
  <Picker.Item label="n/a" />
].concat(values.map(value => {
  ...
}))

@justim
Copy link
Contributor Author

justim commented Jun 18, 2016

The workaround I had so far was indeed to create one list of values and map them to a list of picker items.

Doing the conversion only on mount would not be enough in some cases (my case would be solved, but still), the first item might not always be available in the picker, same goes for any of the values — the children might change.

I'm happy to go either way.

@mkonicek
Copy link
Contributor

Doing the conversion only on mount would not be enough in some cases (my case would be solved, but still), the first item might not always be available in the picker, same goes for any of the values — the children might change.

Could you convert the children to an array only when they change?
https://facebook.github.io/react/docs/component-specs.html

I'd argue, however, that converting children to an array automatically could confusing to the reader - I'd prefer the user to explicitly convert whatever data structure they have to an array for readability and clarity.

@spicyj What do you think?

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 12, 2016
@ghost
Copy link

ghost commented Jul 16, 2016

It's been a while since the last commit was reviewed and the labels show this pull request needs review. Based on the blame information for the files in this pull request we identified @mkonicek as a potential reviewer. Could you take a look please or cc someone with more context?

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 16, 2016
@sophiebits
Copy link
Contributor

Isn't the fact that it needs to be an array an implementation detail of Picker? This seems okay to me and better than what's currently here.

@AzizAK
Copy link

AzizAK commented Aug 23, 2016

@justim i think you can fix it by passing the initial item to the array:

class Example extends Component {

    render() {
        const values = ['1', '2'];
        let pickerItem = []
        pickerItem.push(<Picker.Item label="n/a" value={null} />)
        values.map(value => {
          pickerItem.push(
            <Picker.Item
                label={value}
                value={value}
            />
          )
        })
        return (
            <Picker
                value={this.state.value}
                onValueChange={this.onValueChange.bind(this)}
            >
              {pickerItem}
            </Picker>
        );
    }
}

Please correct me if wrong.

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 23, 2016
@satya164
Copy link
Contributor

@mkonicek : Could you convert the children to an array only when they change?

This can be easily fixed by using a memoized function to get the current children. But is it really necessary? How slow is the conversion?

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 23, 2016
@hramos
Copy link
Contributor

hramos commented Dec 22, 2016

It's been a while since this PR has seen any activity. Is there any interest in landing this, any additional feedback?

@satya164
Copy link
Contributor

@hramos I think we should land this.

@facebook-github-bot facebook-github-bot added GH Review: accepted Import Started This pull request has been imported. This does not imply the PR has been approved. and removed GH Review: review-needed labels Jan 19, 2017
@facebook-github-bot
Copy link
Contributor

I tried to merge this pull request into the Facebook internal repo but some checks failed. To unblock yourself please check the following: Does this pull request pass all open source tests on GitHub? If not please fix those. Does the code still apply cleanly on top of GitHub master? If not can please rebase. In all other cases this means some internal test failed, for example a part of a fb app won't work with this pull request. I've added the Import Failed label to this pull request so it is easy for someone at fb to find the pull request and check what failed. If you don't see anyone comment in a few days feel free to comment mentioning one of the core contributors to the project so they get a notification.

@facebook-github-bot facebook-github-bot added Import Failed and removed Import Started This pull request has been imported. This does not imply the PR has been approved. labels Jan 19, 2017
@everyusernameistaken123

I am experiencing a related issue.
Can't believe it takes 7months to merge 1 changed line?

@satya164
Copy link
Contributor

@facebook-github-bot shipit

@facebook-github-bot facebook-github-bot added Import Started This pull request has been imported. This does not imply the PR has been approved. and removed Import Started This pull request has been imported. This does not imply the PR has been approved. labels Jan 20, 2017
@facebook-github-bot
Copy link
Contributor

I tried to merge this pull request into the Facebook internal repo but some checks failed. To unblock yourself please check the following: Does this pull request pass all open source tests on GitHub? If not please fix those. Does the code still apply cleanly on top of GitHub master? If not can please rebase. In all other cases this means some internal test failed, for example a part of a fb app won't work with this pull request. I've added the Import Failed label to this pull request so it is easy for someone at fb to find the pull request and check what failed. If you don't see anyone comment in a few days feel free to comment mentioning one of the core contributors to the project so they get a notification.

@mkonicek
Copy link
Contributor

mkonicek commented Feb 2, 2017

Trying again.

@facebook-github-bot shipit

@facebook-github-bot facebook-github-bot added Import Started This pull request has been imported. This does not imply the PR has been approved. and removed Import Started This pull request has been imported. This does not imply the PR has been approved. labels Feb 2, 2017
@facebook-github-bot
Copy link
Contributor

I tried to merge this pull request into the Facebook internal repo but some checks failed. To unblock yourself please check the following: Does this pull request pass all open source tests on GitHub? If not please fix those. Does the code still apply cleanly on top of GitHub master? If not can please rebase. In all other cases this means some internal test failed, for example a part of a fb app won't work with this pull request. I've added the Import Failed label to this pull request so it is easy for someone at fb to find the pull request and check what failed. If you don't see anyone comment in a few days feel free to comment mentioning one of the core contributors to the project so they get a notification.

@facebook-github-bot facebook-github-bot added the Import Started This pull request has been imported. This does not imply the PR has been approved. label Mar 15, 2017
@facebook-github-bot
Copy link
Contributor

@javache has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@satya164
Copy link
Contributor

cc @lacker

@facebook-github-bot
Copy link
Contributor

@javache has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

thotegowda pushed a commit to thotegowda/react-native that referenced this pull request May 7, 2017
…a position

Summary:
When using the following component, `this.props.children` is not a flat array.

``` js
class Example extends Component {
    // ...

    render() {
        const values = ['1', '2'];

        return (
            <Picker
                value={this.state.value}
                onValueChange={this.onValueChange.bind(this)}
            >
                <Picker.Item
                    label="n/a"
                    value={null}
                />

                {values.map(value => {
                    return (
                        <Picker.Item
                            label={value}
                            value={value}
                        />
                    );
                })}
            </Picker>
        );
    }
}
```

The resulting `this.props.children` is:

``` js
[
    (child),
    [
        (child),
        (child),
    ],
];
```

Therefor you can't use `this.props.children[2]` to get the last item.

The Android version of the [Picker](https://facebook.github.io/react-native/do
Closes facebook#8153

Differential Revision: D4753480

Pulled By: javache

fbshipit-source-id: deb0264746b39303e66c69c191af0c962db39085
@danielfttorres
Copy link

@justim it's fix this #12829?

@justim
Copy link
Contributor Author

justim commented May 22, 2017

@danielfeelfine, yes, it should. TheReact.Children.toArray call in this PR handles the nested arrays.

@romjear12
Copy link

I used this "hack":

  render() {
    const values = ['1', '2'];

    return (
      <Picker
        value={this.state.value}
        onValueChange={this.onValueChange.bind(this)}
      >
      {
				<Picker
					value={this.state.value}
					onValueChange={this.onValueChange.bind(this)}
				>
				{
					[<Picker.Item
						label="n/a"
						value={null}
					/>].concat(values.map(value => {
							return (
								<Picker.Item
									label={value}
									value={value}
								/>
							)
							})
					) 
				}
				</Picker>
    );
  }

@justim
Copy link
Contributor Author

justim commented Sep 17, 2017

There is no need for hacks anymore, this PR is merged and the example I gave at the top works now.

@hramos hramos added the Merged This PR has been merged. label Mar 8, 2019
@react-native-bot react-native-bot removed the Import Started This pull request has been imported. This does not imply the PR has been approved. label Mar 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.