kirillzyusko / react-native-bundle-splitter

HOC for lazy components loading

Home Page:https://kirillzyusko.github.io/react-native-bundle-splitter/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can add a registerComponent method?

seenyea opened this issue · comments

物流页面need test

Is your feature request related to a problem? Please describe.
can override register api: the complie method

exports.isCached = map_1.isCached;
const defaultPreLoadable = {
    cached: true,
    placeholder: null,
    extract: 'default',
};
let i = 0;

const register = (component) => {
    const enhancedComponent = Object.assign(Object.assign({ name: `Component${i++}` }, defaultPreLoadable), component);
    const { name } = enhancedComponent;
    if (bundler_1.mapLoadable[name] !== undefined) {
        throw new Error(`You try to add new component with already existing name: ${name}`);
    }
    bundler_1.mapLoadable[name] = enhancedComponent;
    return optimized_1.default(name);
};
exports.register = register;

my override

exports.isCached = map_1.isCached;
const defaultPreLoadable = {
    cached: true,
    placeholder: null,
    extract: 'default',
};
let i = 0;
const register = (component) => {
    const enhancedComponent = Object.assign(Object.assign({ name: `Component${i++}` }, defaultPreLoadable), component);
    const { name } = enhancedComponent;

    if (bundler_1.mapLoadable[name] !== undefined) {
        throw new Error(`You try to add new component with already existing name: ${name}`);
    }
    bundler_1.mapLoadable[name] = enhancedComponent;
    return optimized_1.default(name);
};
exports.register = register;

const registerComponent = (component) => {
     const { name = '' } = component;
     if(isCached(name)){
         return optimized_1.default(name);
     }
    return register(component);
}

exports.registerComponent = registerComponent;
``

as **registerComponent** we can use cacheComponent directly or add a new component and use it.

sometimes, a registered page can be used for different tabs

@seenyea I can, but what is the motivation behind it?

Optimized component already do isCached(name) checks. And if component was found in cache, it will mount it in sync way.

If you need to have multiple references to this component, then you can simply create index.js file and put register function there. And import this file everywhere you want. Once first usage will be loaded all others will automatically use cached version.

Did I answer on your question?

can I add it myslef?

@seenyea yes, you can. You can simply import necessary functions into your code and re-create this function in your codebase. But why? The code above doesn't make any sense and I don't see any reasons to use it. OptimizedComponent already use if(isCached(name)) checks. And if component found in cache it will immediately render it.

If you need to have multiple usage of one component, then you can create index.js file and register your component there:

// index.js

export default register({
  require: () => require("./View"),
  name: "Tab"
});

And import this file where you want. If it has multiple usages - you can add several import statements. This component will not be loaded until you start using it (until it will be really displayed). Once one usage of this component will be loaded - all others will use it from cache.

Does it make sense?

for react native v3 I crate a TopTabNavigator
lib.js

 function createTopTabNavigator(
    routeConfigMap: NavigationRouteConfigMap,
    drawConfig?: DUTabNavigatorConfig
)

view.js

const routeConfigMap = {...};
const drawConfig = {...}
const tab = createTopTabNavigator(routeConfigMap, drawConfig);
class Page extends React.Component{
         static router = tab.router
         render(){
               return <div>test</div>
         }
}

index.js

register({ 
  require: () => require('./view'), 
  static: { 
    navigationOptions: ({ navigation }) => { 
      console.log('recommend => ');
      return {title: navigation.getParam('title')};
    },
    router: //here are I need "tab.router "too, how can I do it?
  } 
})

for react native v3 I crate a TopTabNavigator
lib.js

function createTopTabNavigator(
routeConfigMap: NavigationRouteConfigMap,
drawConfig?: DUTabNavigatorConfig
)
view.js

const routeConfigMap = {...};
const drawConfig = {...}
const tab = createTopTabNavigator(routeConfigMap, drawConfig);
class Page extends React.Component{
static router = tab.router
render(){
return

test

}
}
index.js

register({
require: () => require('./view'),
static: {
navigationOptions: ({ navigation }) => {
console.log('recommend => ');
return {title: navigation.getParam('title')};
},
router: //here are I need "tab.router "too, how can I do it
}
})

if I have two pages: page1 and page2 as below:
page1.js

import Test from './index.js'

page2.js

import Test from './index.js'

what happen?
throw an error: You try to add new component with already existing name: xxxx

can you give me some advices?

I try this way:

import { register, isCached, preload } from 'react-native-bundle-splitter';

const compName = 'RecTab';
const RecTab = isCached(compName) ? preload().component(compName) : register({ 
  require: () => require('./view'), 
  name: compName,
  static: { 
    navigationOptions: ({ navigation }) => { 
      console.log('recommend => ');
      return {title: navigation.getParam('title')};
    }
  } 
});

export default RecTab;

but the error still look at me, can you give some advice?

@seenyea

here are I need "tab.router "too, how can I do it?

const routeConfigMap = {...};
const drawConfig = {...}
const tab = createTopTabNavigator(routeConfigMap, drawConfig);

register({ 
  require: () => require('./view'), 
  static: { 
    navigationOptions: ({ navigation }) => { 
      console.log('recommend => ');
      return {title: navigation.getParam('title')};
    },
    router: tab.router,
  } 
})

But that's strange, that your components are aware about navigators where this component will be used.

I try this way:

That's wrong, because isCached may return false several times, and you will attempt to register component several times (and you will see error - it's expected behavior).

For me it seems, that you use API in wrong way. You should call register only one time for one component. This function will return you react component (react component will return null from render, when component isn't loaded and will return component, when it will be loaded).

You should call preload only when you know, that this component will be soon displayed (for example user passed Login screen -> you can call preload().component('Dashboard') because this screen will be visible after login).

You shouldn't use isCached in your code at all. I exported this function in order to gave a control for developers over information about what is located in cache.

It's hard to gather all information from small samples of code. If it's possible, please, create small reproducible demo with your issue/bug. Thanks in advance!

sorry about it,
createTopTabNavigator is the same as createMaterialTopTabNavigator
you can find document here https://reactnavigation.org/docs/3.x/material-top-tab-navigator

I think preload().component is an async way, can get a sync way?

I think preload().component is an async way, can get a sync way?

It's I/O operation. It should be async.

createTopTabNavigator is the same as createMaterialTopTabNavigator

Are you trying to make lazy tab bars? I mean you are trying to make entire container lazy, not separate screens, right?

The most confusing part of app for me is:

static router = tab.router

I used many times tab navigators in different versions and I haven't extracted any properties from that like you do.
Can you explain why you do it? You can simply attach a link, where I can read about it.

Are you trying to make lazy tab bars? I mean you are trying to make entire container lazy, not separate screens, right?
yes, any idea for me.

Can you explain why you do it?
now I rewrite an old project(enhance performance), all the tabs use same function createTopTabNavigator which custom tabBarComponent, then return React.component which has a static prop router.

In register api, I need rewrite static props as your document statement, how can rewrite createTopTabNavigator

code like this(lot of pages use createTopTabNavigator):

import React, {Component} from 'react';
import {Animated, View, StyleSheet, Dimensions} from 'react-native';

import {
  createMaterialTopTabNavigator,
  MaterialTopTabBar,
  NavigationRouteConfigMap,
  TabNavigatorConfig
} from "react-navigation";
import PropTypes from "prop-types";

const screenWidth = Dimensions.get('window').width;

export type DUTopTabNavigatorProps = {
  setBadge: (index: { show: boolean, count: number }) => void
};

export interface DUTabNavigatorConfig extends TabNavigatorConfig{
  badgeStyle?: PropTypes;
}

function createTopTabNavigator(
    routeConfigMap: NavigationRouteConfigMap,
    drawConfig?: DUTabNavigatorConfig
): React.Component {
  const {tabNum =4} = drawConfig || {};

  class TabBar extends MaterialTopTabBar {
  ....
  }

  const config = Object.assign({
    tabBarComponent: TabBar,
    tabBarOptions: {
       ...
    },
    ....
  }, drawConfig || {});

  const TabNavigator = createMaterialTopTabNavigator(
      routeConfigMap,
      config);

  class Page extends Component {
    static router = TabNavigator.router;
    constructor(props) {
      super(props);
      this.state = {
        badge: {}
      };
    }

    componentDidAppear() {

    }
    render() {
      return <TabNavigator navigation={this.props.navigation} screenProps={{badge: this.state.badge}}/>
    }
  }

  return Page;
}

const styles = StyleSheet.create({
  label: {
    textAlign: 'center',
    fontSize: 13,
    margin: 8,
    backgroundColor: 'transparent',
  }
});

export {createTopTabNavigator};

Hi @seenyea

You can not make entire tab bar lazy in react-navigation v3. I gave detailed answer on that in this comment. Unfortunately it's a restriction of react-navigation <= v4.

I would recommend you to wrap separate screens into register (which are used in TabBar). In this case everything will work properly and you will not have issues.

Actually, I make it work today.
code like this:

common.tab.js

import React from 'react';
import {Animated, View, StyleSheet, Dimensions} from 'react-native';

import {
  createMaterialTopTabNavigator,
  MaterialTopTabBar,
  NavigationRouteConfigMap,
  TabNavigatorConfig
} from "react-navigation";

const screenWidth = Dimensions.get('window').width;

export type DUTopTabNavigatorProps = {
  setBadge: (index: { show: boolean, count: number }) => void
};

export interface DUTabNavigatorConfig extends TabNavigatorConfig{
  badgeStyle?: PropTypes;
}

const __tabRoute__ = {};//cache the tab route;

function createTopTabNavigator(
    routeConfigMap: NavigationRouteConfigMap,
    drawConfig?: DUTabNavigatorConfig,
    name: ''
): React.Component {
  const {tabNum =4} = drawConfig || {};

  class TabBar extends MaterialTopTabBar {
  }

  const config = Object.assign({
    tabBarComponent: TabBar,
    ...
  }, drawConfig || {});


  const TabNavigator = __tabRoute__[name] || createMaterialTopTabNavigator(
      routeConfigMap,
      config);

  __tabRoute__[name] = TabNavigator;

  return TabNavigator;
}

const styles = StyleSheet.create({
  label: {
    textAlign: 'center',
    fontSize: 13,
    margin: 8,
    backgroundColor: 'transparent',
  }
});

export {createTopTabNavigator};

HomeTab.js

import React from 'react';
import {Dimensions} from 'react-native';
import px2dp from '../../utils/px2dp';
import { createTopTabNavigator } from './common.tab.js';

export const HomeTab = createTopTabNavigator(
    {
        ...
    },
    {
       ...
    },
    'homeNavi'
);

Home.js

import React from 'react';
...
import { register, getComponent, isCached } from '../../utils/split';
import { HomeTab } from './HomeTab';

const name = 'Home';
const staticProps = { 
    navigationOptions: ({ navigation }) => { 
      return {
         ...
      }
    },
    router: HomeTab.router
  };

const BundleComponent = isCached(name) ? getComponent(name) : register({
  require: () => require('./HomeView'), 
  name,
  static: {...staticProps}
});

export default BundleComponent;

HomeTab.js

import React from 'react';
import { HomeTab } from './HomeTab';

@screen('Home')
class Home extends React.Component{

    constructor(props) {
        super(props);
       ....
    }

    componentDidMount() {
         ...
   }

    render() {
        return <HomeTab navigation={this.props.navigation} screenProps={{badge: 0}}/>
    }
}

export default Home;

@seenyea why HomeView needs to know anything about router?

why HomeView needs to know anything about router?
I'm not sure router is needed for HomeView.
It is generated by createMaterialTopTabNavigator, so I do not ignore it.
do you have any idea for this?

@seenyea no, I don't have any ideas why it's needed. And also I can not find any information about it in documentation. If you remove it - will app work without it?

Closed due to the inactivity.