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

Fix: RefreshControl in FlatList makes borderWidth not working #24411

Closed

Conversation

Nizarius
Copy link
Contributor

@Nizarius Nizarius commented Apr 11, 2019

Summary

Fixes #22752

On line 1021 you are passing base style to props:
style: [baseStyle, this.props.style],

Explicitly passing base style to ScrollView just overrides this line and doesn't let developers to customise style of any inheritors of ScrollView (not only FlatList) with custom RefreshControl.

So this line (1113) seems to be removed.

Changelog

[GENERAL] [Fixed] - fix of Android's bug that doesn't let override ScrollView's Style with custom RefreshControl.

Test Plan

Use this code snippet to test that passing RefreshController doesn't break styling of ScrollView on Android.

type Props = {};
export default class App extends Component<Props> {
  state = { isLoading: false };

  reload = () => {
    this.setState({ isLoading: true });

    setTimeout(() => {
      this.setState({ isLoading: false });
    }, 2000);
  };
  render() {
    return (
      <ScrollView
        style={{
          flex: 1,
          alignSelf: "stretch",
          borderWidth: 10,
          borderColor: "red"
        }}
        refreshControl={
          <RefreshControl
            colors={["red", "yellow"]}
            refreshing={this.state.isLoading}
            onRefresh={() => this.reload()}
          />
        }
      >
        <View
          style={{
            width: "100%",
            height: 300
          }}
        >
          <Text>3335</Text>
        </View>
        <View
          style={{
            width: "100%",
            height: 300
          }}
        />
        <View
          style={{
            width: "100%",
            height: 300
          }}
        />
      </ScrollView>
    );
  }
}

The same for FlatList:

type Props = {};
export default class App extends Component<Props> {
  state = { isLoading: false };

  reload = () => {
    this.setState({ isLoading: true });

    setTimeout(() => {
      this.setState({ isLoading: false });
    }, 2000);
  };
  render() {
    return (
       <FlatList
        style={{
          flex: 1,
          alignSelf: "stretch",
          borderWidth: 10,
          borderColor: "red"
        }}
        data={["a", "b", "c"]}
        renderItem={({ item }) => (
          <View style={{ height: 500 }}>
            <Text>{item}</Text>
          </View>
        )}
        refreshControl={
          <RefreshControl
            colors={["red", "yellow"]}
            refreshing={this.state.isLoading}
            onRefresh={() => this.reload()}
          />
        }
      />
    );
  }
}

@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 Apr 11, 2019
Copy link
Contributor

@janicduplessis janicduplessis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue here is that if we remove this line some styles will be applied twice, both on AndroidSwipeRefreshLayout and the ScrollView (here and here). Can you verify that adding a style like padding or margin doesn't get applied twice.

@Nizarius
Copy link
Contributor Author

Nizarius commented Apr 12, 2019

@janicduplessis yeah, you're right. In fact, margin properties only work on AndroidSwipeRefreshLayout and padding properties - only on ScrollView. So padding or margin doesn't get applied twice. But there is such a problem with opacity.
So the ideal solution seems something like that:

  1. Extract all margin properties ('margin', 'marginRight' etc) and opacity from this.props.style and apply it to AndroidSwipeRefreshLayout (with baseStyle).
  2. Pass other style properties (padding, borders etc) to ScrollView (with baseStyle).
    This can prevent unexpected behaviour in the future as we won't duplicate any properties to both views.

I don't know if you have some utility functions for extracting properties' family from style ("extract all margin properties" or something similar) to make code cleaner and more declarative. If you have I would use it.

What do you think?

@janicduplessis
Copy link
Contributor

I don't think we have anything currently to do this. I have something like this in an app though:

const OUTER_PROPS = {
  margin: true,
  marginHorizontal: true,
  marginVertical: true,
  marginBottom: true,
  marginTop: true,
  marginLeft: true,
  marginRight: true,
  flex: true,
  flexGrow: true,
  flexShrink: true,
  flexBasis: true,
  alignSelf: true,
  height: true,
  minHeight: true,
  maxHeight: true,
  width: true,
  minWidth: true,
  maxWidth: true,
  position: true,
  left: true,
  right: true,
  bottom: true,
  top: true,
};

export function splitLayoutProps(props) {
  const inner = {};
  const outer = {};
  Object.keys(props).forEach(k => {
    if (OUTER_PROPS[k] === true) {
      outer[k] = props[k];
    } else {
      inner[k] = props[k];
    }
  });
  return { outer, inner };
}

You could also use StyleSheet.flatten to make sure to have an object from the style prop.

@sahrens What do you think about this?

@Nizarius
Copy link
Contributor Author

Nizarius commented Apr 16, 2019

@janicduplessis seems nice. We need to define where to place this utility function and OUTER_PROPS dictionary in the project.

@cpojer
Copy link
Contributor

cpojer commented Apr 30, 2019

What's the status of this PR?

@Nizarius
Copy link
Contributor Author

@cpojer I suggest, we are waiting comments for the best code styling. The implementation itself will be fast.

@sahrens
Copy link
Contributor

sahrens commented Apr 30, 2019

Yeah let's add a splitLayoutProps export on StyleSheet and use that.

@Nizarius Nizarius force-pushed the fix_android_scroll_view_style branch 2 times, most recently from 134292e to 130b720 Compare May 1, 2019 18:36
@Nizarius
Copy link
Contributor Author

Nizarius commented May 2, 2019

@sahrens @janicduplessis I've added splitLayoutProps to export with some tests to cover its functionality.
I'm also explicitly passing baseStyle to both wrapper's and container's styles to be sure that we don't break anything:

return React.cloneElement(
          refreshControl,
          {style: [baseStyle, outer]},
          <ScrollViewClass
            {...props}
            style={[baseStyle, inner]}
            // $FlowFixMe
            ref={this._setScrollViewRef}>
            {contentContainer}
          </ScrollViewClass>,
        );

But as I check it works without it. So it's up to you whether to leave it or not.

@Nizarius
Copy link
Contributor Author

Nizarius commented May 27, 2019

Any news?)

Copy link
Contributor

@cpojer cpojer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. Can you rebase it on top of master and use relative requires instead + remove the .vscode/settings.json file? That file shouldn't go into this PR.

@Nizarius
Copy link
Contributor Author

Nizarius commented Jun 5, 2019

@cpojer yep, will do it soon

@Nizarius Nizarius force-pushed the fix_android_scroll_view_style branch 2 times, most recently from 4639a07 to 640211f Compare June 6, 2019 18:41
@Nizarius
Copy link
Contributor Author

Nizarius commented Jun 6, 2019

@cpojer done

@cpojer cpojer force-pushed the fix_android_scroll_view_style branch from 640211f to 7862643 Compare June 7, 2019 09:22
Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cpojer is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@react-native-bot
Copy link
Collaborator

This pull request was successfully merged by @Nizarius in d9a8ac5.

When will my fix make it into a release? | Upcoming Releases

@react-native-bot react-native-bot added the Merged This PR has been merged. label Jun 7, 2019
kelset pushed a commit that referenced this pull request Jun 7, 2019
Summary:
Fixes #22752

On line 1021 you are passing base style to props:
`style: [baseStyle, this.props.style],`

Explicitly passing base style to ScrollView just overrides this line and doesn't let developers to customise style of any inheritors of ScrollView (not only FlatList) with custom RefreshControl.

So this line (1113) seems to be removed.

## Changelog

[GENERAL] [Fixed] - fix of Android's bug that doesn't let override ScrollView's Style with custom RefreshControl.
Pull Request resolved: #24411

Differential Revision: D15713061

Pulled By: cpojer

fbshipit-source-id: 461259800f867af15e53e0743a5057ea4528ae69
M-i-k-e-l pushed a commit to M-i-k-e-l/react-native that referenced this pull request Mar 10, 2020
…ok#24411)

Summary:
Fixes facebook#22752

On line 1021 you are passing base style to props:
`style: [baseStyle, this.props.style],`

Explicitly passing base style to ScrollView just overrides this line and doesn't let developers to customise style of any inheritors of ScrollView (not only FlatList) with custom RefreshControl.

So this line (1113) seems to be removed.

## Changelog

[GENERAL] [Fixed] - fix of Android's bug that doesn't let override ScrollView's Style with custom RefreshControl.
Pull Request resolved: facebook#24411

Differential Revision: D15713061

Pulled By: cpojer

fbshipit-source-id: 461259800f867af15e53e0743a5057ea4528ae69
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Component: FlatList Component: RefreshControl Merged This PR has been merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RefreshControl in FlatList makes borderWidth not working
7 participants