Skip to content

Root App Component State Rendering Issue #22

@nionata

Description

@nionata

Our root component was originally a functional component with hooks. I noticed this odd behavior though. Every time setMessages was called the new message would be retained, but the previous array would be cleared. Additionally, the bluetooth manager would be reinitialized. Since it is inside of useEffect that could only mean that the component is being mounted or updated each time the state is changing. Super odd behavior and not desirable at all.

const App = () => {
  const [messages, setMessages] = useState<Message[]>([])

  useEffect(() => {
    const bluetoothManager = new BluetoothManager(
      BluetoothMode.Advertise, 
      () => messages,
      (message: Message) => {
        console.log(messages, message)
        setMessages([...messages, message])
      }
    )
    bluetoothManager.start()

    return () => {
      // Cleanup logic
    }
  })

  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName: string = '';

            if (route.name === 'GrapeVine') {
              iconName = focused ? 'home' : 'home-outline';
            } else if (route.name === 'Peers') {
              iconName = focused ? 'bluetooth' : 'bluetooth-outline';
            } else if (route.name === 'Settings') {
              iconName = focused ? 'cog' : 'cog-outline';
            }

            // You can return any component that you like here!
            return <Ionicons name={iconName} size={size} color={color} />;
          },
          tabBarActiveTintColor: 'blueviolet',
          tabBarInactiveTintColor: 'gray',
        })}
      >
        <Tab.Screen name="GrapeVine" children={() => <HomeScreen messages={messages}/>} />
        <Tab.Screen name="Peers" component={ScanScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

export default App;

I tried to read up on functional components, but I wasn't enlightened much. I rewrote the component in the OG class syntax and it now it is working as desired. I'm going to leave the class version for now, but I would love to know what's going on here.

interface AppProps {
}
interface AppState {
  messages: Message[]
}

class App extends React.Component<AppProps, AppState> {
  constructor(props: AppProps) {
    super(props)
    this.state = {
      messages: []
    }
  }

  componentDidMount() {
    const bluetoothManager = new BluetoothManager(
      BluetoothMode.Advertise, 
      () => this.state.messages,
      (message: Message) => {
        console.log(this.state.messages, message)
        this.setState((state) => {
          return {
            messages: [...state.messages, message]
          }
        })
      }
    )
    bluetoothManager.start()
  }

  render() {
    return (
      <NavigationContainer>
        <Tab.Navigator
          screenOptions={({ route }) => ({
            tabBarIcon: ({ focused, color, size }) => {
              let iconName: string = '';
  
              if (route.name === 'GrapeVine') {
                iconName = focused ? 'home' : 'home-outline';
              } else if (route.name === 'Peers') {
                iconName = focused ? 'bluetooth' : 'bluetooth-outline';
              } else if (route.name === 'Settings') {
                iconName = focused ? 'cog' : 'cog-outline';
              }
  
              // You can return any component that you like here!
              return <Ionicons name={iconName} size={size} color={color} />;
            },
            tabBarActiveTintColor: 'blueviolet',
            tabBarInactiveTintColor: 'gray',
          })}
        >
          <Tab.Screen name="GrapeVine" children={() => <HomeScreen messages={this.state.messages}/>} />
          <Tab.Screen name="Peers" component={ScanScreen} />
          <Tab.Screen name="Settings" component={SettingsScreen} />
        </Tab.Navigator>
      </NavigationContainer>
    );
  }
}

export default App;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions