React-native-tab-view: On state change not re-render

Created on 22 Aug 2016  路  13Comments  路  Source: satya164/react-native-tab-view

Hi Team,

If state change then It'll not render again, I need to re render content when state change.
Plz suggest me

Most helpful comment

@ethanyuwang https://github.com/react-native-community/react-native-tab-view#scenemap

All the scenes rendered with SceneMap are optimized using React.PureComponent and don't re-render when parent's props or states change. If you don't want this behaviour, or want to pass additional props to your scene components, use renderScene directly instead of using SceneMap.

All 13 comments

Hey! It'll only re-render if the navigationState changes. If you want it to re-render on any other change, add that prop to the navigationState object.

e.g - say you have a loaded prop which should trigger a re-render, you could go with something like this,

state = {
    routes: [ ... ],
    loaded: true,
}

...

<TabViewAnimated
    navigationState={this.state}

...

routes : [ ... ], generate error here

@uc-asa that's just an example. Can you post your code here so I can say what changes you need to do?

Also added this to the readme which should give you a better idea, https://github.com/react-native-community/react-native-tab-view#caveats

I have created a function for search and created using tab view
showarr () {
var s = [];
if(!this.state.isLoading && this.arr.length > 0) {
for(let i in this.arr){
try {
if(this.state.text != '') {
if(((this.arr[i]['snippet']).toLowerCase()).indexOf((this.state.text).toLowerCase()) > -1 || ((this.arr[i]['content']).toLowerCase()).indexOf((this.state.text).toLowerCase()) > -1) {
s.push(

                                <Text style={styles.toc_content} >{this.arr[i]['content']}</Text>
                            </View>
                        )
                    }
                }
                else {
                    s.push(
                        <View key={i} style={[styles.pmd,styles.mtMd,styles.marginWidth]}>
                            <Text style={styles.toc_content} >{this.arr[i]['content']}</Text>
                        </View>
                    )
                }
            }
            catch(err) {
                console.log("Some error occur" + err);
            }
        }
    }
    return s;
}

//
_renderScene = ({ route }) => {
switch (route.key) {
case '1':
return {this.showarr()};
default:
return null;
}
};

render() {
return (

style={styles1.container}
navigationState={this.state.navigation}
renderScene={this._renderPage}
renderHeader={this._renderHeader}
onRequestChangeTab={this._handleChangeTab}
navigationState={this.state}
/>

);
}

@uc-asa You can just put the items in this.state.navigation to this.state directly, e.g. -

What you have,

{
    text: '',
    isLoading: false,
    navigation: {
       index: 0,
       routes: [],
    },
}

Change it to,

{
    text: '',
    isLoading: false,
    index: 0,
    routes: [],
}

And the in your render, where you're doing navigationState={this.state.navigation}, just do navigationState={this.state} instead.

I have keep more variable in this.state so I have created
this.state = {
navigation: {
index: 0,
routes: [
{ key: '1', title: 'Table of content' },
],
text: '',
}
}
and I updated using
let navigation = this.state.navigation;
navigation['text'] = text;
this.setState({ navigation: navigation });

console.log(this.state.navigation) // It print value of text but unable to re-render

The problem with your code is actually here,

let navigation = this.state.navigation;
navigation['text'] = text;
this.setState({ navigation: navigation });

You're mutating the navigation object. You should do this instead,

let navigation = this.state.navigation;
this.setState({
    navigation: { ...navigation, text },
});

I'd suggest you do the following instead,

instead of what you're doing, do this,

this.state = {
    index: 0,
    routes: [
        { key: '1', title: 'Table of content' },
    ],
    text: '',
}

Then, to update,

this.setState({ text: text });

and instead of navigationState={this.state.navigation}, do navigationState={this.state}

Lemme know if it worked or not.

Its not work but I have done by another way
Thanks

Having the same problem.

My TabView has navigationState prop:

<TabView
          style={styles.editorContainer}
          navigationState={this.state}
          renderTabBar={this._renderTabBar}
          renderScene={SceneMap({
            text: this._renderText,
            paragraph: this._renderParagraph,
          })}
          onIndexChange={index => this.setState({ index })}
/> 

My _renderText method is as below:

  _renderText = () => {
    return (
      <ScrollView style={styles.container}>
        {this._renderTextButton()}
        {this._renderTextStyleButton()}
        {this._renderColorButton(TEXT_COLOR)}
        {this._renderColorButton(BACKGROUND_COLOR)}
        {this._renderTextClearFormatButton()}
      </ScrollView>
    )
  }

and inside _renderTextStyleButton, I have a Text element that displays a string inside state:

<Text style={styles.text}>
            {this.state.currentTextStyleName}
</Text>

However, after this.state.currentTextStyleName has been updated to other value, Text still renders the same string. What am I missing?

@ethanyuwang https://github.com/react-native-community/react-native-tab-view#scenemap

All the scenes rendered with SceneMap are optimized using React.PureComponent and don't re-render when parent's props or states change. If you don't want this behaviour, or want to pass additional props to your scene components, use renderScene directly instead of using SceneMap.

still no luck. I am using filter in my component but it does not rerender on updating the state and i am also not using SceneMap. Please help
Thanks in advance.

<TabView
          navigationState={{ index, routes }}
          renderScene={({ route }) => {
            switch (route.key) {
              case "first":
                return this.HomeRoute();
              case "second":
                return this.PendingRoute();
              case "third":
                return this.AcceptedRoute();
              default:
                return null;
            }
          }}
          onIndexChange={(index) => this.setState({ index })}
          initialLayout={initialLayout}
          style={{ color: "red" }}
          renderTabBar={(props) => (
            <TabBar
              {...props}
              labelStyle={styles.tabBarText}
              indicatorStyle={styles.tabBarBorder}
              style={styles.tabBar}
            />
          )}
        />
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jouderianjr picture jouderianjr  路  3Comments

glennvgastel picture glennvgastel  路  3Comments

lubomyr picture lubomyr  路  3Comments

KingAmo picture KingAmo  路  3Comments

t3chnoboy picture t3chnoboy  路  3Comments