在本机平面清单项目中渲染Admob标语

时间:2019-07-07 10:24:29

标签: react-native-firebase

我已将react-native-firebase和AdMob模块集成到我的react本机项目中,并且一切都按预期工作(测试广告和生产中的广告)。现在,我想在我的平面列表中添加横幅(每X行数渲染一个横幅)。

这是我从服务器接收的数据的示例:

[
  {
   ...item 1 details
  },{
   ...item 2 details
  },{
   ...ad details
  },{
   ...item 3 details
  },{
   ...item 4 details
  },{
   ...ad details
  }
]

这是平面列表组件

class ItemsList extends React.Component {
  _renderItem = ({item, index}) => {

    if (item.isAd) {
      const unitId = Platform.OS === "ios" ? item.adIdIOS : item.adIdAndroid;
      const Banner = firebase.admob.Banner;
      const AdRequest = firebase.admob.AdRequest;
      const request = new AdRequest();
      const keyWords = item.admobKeywords || [];
      keyWords.forEach(keyword => {
        request.addKeyword(keyword);
      });

      return (
        <View style={{ width:"100%", height: item.adHeight || "auto", marginTop: 5, marginBottom: 15, alignItems: 'center', justifyContent: 'center' }}>
          <Banner
            size={item.adSize}
            request={request.build()}
            unitId={unitId}
            onAdLoaded={() => {}}
          />
        </View>
      )

    } else {
     renderItem()
    }
  }

  render() {
    return(
        <View>
          <FlatList 
            data={this.state.data}
            renderItem={this._renderItem}
            ...
          />
        </View>
    )
  };
};

问题在于,每当发生滚动事件(用户向下滚动)时,Flatlist都会重新渲染横幅(触发新请求),并且横幅会不断刷新。一段时间后,许多请求被触发,应用程序崩溃!

我知道在renderItem方法内调用网络请求不是一个好习惯,因此我也尝试了以下方法,但问题仍然相同:

const Banner = firebase.admob.Banner;
const AdRequest = firebase.admob.AdRequest;
const request = new AdRequest();

class CatalogueSalesList extends React.Component {
  _renderItem = ({item, index}) => {

    if (item.isAd) {
      const unitId = Platform.OS === "ios" ? item.adIdIOS : item.adIdAndroid;
      const keyWords = item.admobKeywords || [];
      keyWords.forEach(keyword => {
        request.addKeyword(keyword);
      });

      return (
        <View style={{ width:"100%", height: item.adHeight || "auto", marginTop: 5, marginBottom: 15, alignItems: 'center', justifyContent: 'center' }}>
          <Banner
            size={item.adSize}
            request={request.build()}
            unitId={unitId}
            onAdLoaded={() => {}}
          />
        </View>
      )

    } else {
     renderItem()
    }
  }

  render() {
    return(
        <View>
          <FlatList 
            data={this.state.data}
            renderItem={this._renderItem}
            ...
          />
        </View>
    )
  };
};

有人可以为我提供一个解决方案,说明如何在Flatlist内实施横幅广告,而无需在用户每次滚动列表时重新呈现横幅?

我使用的版本:

"react-native": "0.59.9",
"react-native-firebase": "~5.5.3"

1 个答案:

答案 0 :(得分:0)

Flatlist组件包含onScroll事件挂钩,可用于确定何时以及什么类型的滚动发生: onScrollBeginDragonScrollEndDragonMomentumScrollBeginonMomentumScrollEnd

使用这些内容,并使横幅组件/列表项成为有状态组件。 以下代码仅在用户不滚动且只有一次时才会呈现admob内容(及其相关的网络请求)。

如果标语组件直接来自admob,则将其包装在有状态的组件中,并执行以下操作。

List Parent Component

class CatalogueSalesList extends React.Component {
  constructor() {
    this.state = {
      isDragging: false,
      isGliding: false,
  }

  _renderItem = ({item, index}) => {
      return (
        <View>
          <Banner
            isDragging={this.state.isDragging}
            isGliding={this.state.isGliding}
            size={item.adSize}
            request={request.build()}
            unitId={unitId}
            onAdLoaded={() => {}}
          />
        </View>
      )

    } else {
     renderItem()
    }
  }

  render() {
    return(
        <View>
          <FlatList
            onScrollBeginDrag={
              () => {this.setState({isDragging: true});}
            }
            onScrollEndDrag={
              () => {this.setState({isDragging: false});}
            }
            onMomentumScrollBegin={
              () => {this.setState({isGliding: true});}
            }
            onMomentumScrollEnd={
              () => {this.setState({isGliding: false});}
            }
            data={this.state.data}
            renderItem={this._renderItem}
            ...
          />
        </View>
    )
  };
};

Banner.tsx

class Banner extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            shouldRenderAd: false,
        }
    }

    componentDidMount() {
        if (!this.props.isGliding && !this.props.isDragging) {
            this.setState({
                shouldRenderAd: true,
            });
        }
    }

    shouldComponentUpdate(nextProps: Props): boolean {
        if (this.state.shouldRenderAd) {
            // if it has already rendered the ad, don't re-render
            return false;
        } else if (!nextProps.isDragging && !nextProps.isGliding) {
            // if stationary, ok to re-render
            return true;
        } else if (nextProps.isDragging && !nextProps.isGliding) {
            // if dragging, but not gliding, ok to re-render
            return true;
        } else {
            // otherwise (it is gliding) don't re-render
            return false;
        }
    }

    componentDidUpdate() {
        if (!this.props.isGliding && !this.props.isDragging) {
            // if no scrolling is happening
            this.setState({
                shouldRenderAd: true,
            });
        }
    }

    render() {
        if (this.state.shouldRenderAd) {
            return (
                // render your admob (network requests) stuff here
            );
        } else {
            return (
                // Placeholder component for your ad
                // probably an empty view the same dimensions as the ad banner
            );
        }
    }
}