Expo / React Native TabView在状态更改时重新呈现组件/选项卡

时间:2019-04-06 19:57:22

标签: react-native expo

我正在使用Expo(React Native框架)编写应用程序。每当使用setState(...)方法更改组件的状态时,组件都应重新渲染以显示最新的状态数据。这适用于基本的React Native组件,例如View,Text,Button(我已经尝试了这三个组件),但是在这里我没有使用自定义组件TabView进行重新渲染。有关组件的文档中对此进行了说明:

“使用SceneMap渲染的所有场景均使用React.PureComponent进行了优化,并且在父项的道具或状态发生更改时不会重新渲染。如果您需要更多控制场景更新方式的信息(例如-即使发生触发重新渲染navigationState不变),请直接使用renderScene而不是使用SceneMap。“

我不太了解如何进行管理。我希望在状态更改时重新渲染组件,在这种情况下,在单击按钮并调用函数writeData()之后。

TabView组件的文档在这里:https://github.com/react-native-community/react-native-tab-view

import React from 'react';
import { TabView, SceneMap } from 'react-native-tab-view';

import { StyleSheet, Text, View, Dimensions, Button, ToastAndroid } from 'react-native';

export default class MojTabView extends React.Component {
state = {
    index: 0,
    routes: [
      { key: 'allEvents', title: 'Všetko' },
      { key: 'sortedEvents', title: 'Podľa druhu' },
      { key: 'myEvents', title: 'Moje akcie'}
    ],
    name: "Robert"
  };

MyEvents = () => (
    <View style={[styles.scene, { backgroundColor: 'white' }]}>
        <Text>Some content</Text>
        <Button
          style={{ margin: 5 }}
          onPress={this.writeData}
          title="Write data"
          color="#841584"
        />
        <Text>Name in state: {this.state.name}</Text>
    </View>
  );

SortedEvents = () => (
      <Text>Some content</Text>
);

AllEvents = () => (
     <Text>Some other content</Text>
);

writeData = () => {
  ToastAndroid.show("button click works!", ToastAndroid.LONG);
  this.setState({ name: "Richard"});

}
render() {
    return (
        <TabView
          navigationState={this.state}
          renderScene={SceneMap({
              allEvents: this.AllEvents,
              myEvents: this.MyEvents,
              sortedEvents: this.SortedEvents
          })}
          onIndexChange={index => this.setState({ index })}
          initialLayout={{ width: Dimensions.get('window').width }}
        />
    );
}

}

我花了几个小时试图实现这一目标,但没有解决方案。这是我的第一个StackOverflow问题,谢谢。

3 个答案:

答案 0 :(得分:1)

好的,我终于能够提出一个不错的解决方案。关键是要在一个单独的文件中将各个选项卡/路由的内容定义为具有自身状态的典型React Native组件,而不是在此MyTabView组件内部,就像在TabView文档中的示例中所做的那样。然后它会按预期工作。

简单的例子: 这是选项卡之一的内容:

import React from 'react';
import { Text, View, Button } from 'react-native';

export default class MyExampleTab extends React.Component {
state = {
    property: "Default value",
}

writeData = () => {
    this.setState({
        property: "Updated value"
   })
}

render() {
    return (
        <View>
            <Button
            style={{ margin: 5 }}
            onPress={this.writeData}
            title="Change the state and re-render!"
            color="#841584"
            />
            <Text>Value of state property: {this.state.property}</Text>
        </View>
    )
}
}

这是我在MyTabView组件中引用它的方式:

 import MyExampleTab from './MyExampleTab'
 ...
 export default class MyTabView extends React.Component {
 ...
       render() {
           return (
              <TabView
                  navigationState={this.state}
                  renderScene={SceneMap({
                       ...
                       someKey: MyExampleTab,
                       ...
                  })}
                  onIndexChange={index => this.setState({ index })}
                  initialLayout={{ width: Dimensions.get('window').width }}
              />
         )

因此,我不像通常使用自定义组件那样使用<MyExampleTab />,而是按原样编写MyExampleTab。这很有意义。然后在按钮上单击状态更改,然后重新渲染选项卡。

答案 1 :(得分:0)

应重新触发TabView的两种状态是:

  • 索引。
  • 路线

他们这样做是出于性能优化的目的

如果您要在更改与这些值无关的任何其他状态值时强制重新渲染TabView,则根据文档...您需要提供renderScene自己的实现,例如:

renderScene =({route,jumpTo})=> {   切换(route.key){     案例“音乐”:       回报;     案例“相册”:       回报;   } };

在这种情况下:

  

您需要确保您的个人路线实施了   应该改善组件的性能。

答案 2 :(得分:0)

以@druskacik上面的内容为基础,实际上您也可以传递带有道具的组件

import MyExampleTab from './MyExampleTab'
 ...
 export default class MyTabView extends React.Component {
 ...
       render() {
           return (
              <TabView
                  navigationState={this.state}
                  renderScene={SceneMap({
                       ...
                       someKey:() => <MyExample foo={foodata} />,
                       ...
                  })}
                  onIndexChange={index => this.setState({ index })}
                  initialLayout={{ width: Dimensions.get('window').width }}
              />
         )