Dave Chambers
Dave Chambers

Reputation: 2563

React Native view renders incorrectly after Redux data is updated

I am using react-redux and have a simple Grid with react-native-easy-grid. It lays out a set of Pegs (circles) correctly.

When I change the settings, for example numPosInCode from 6 to 5, the code in the ColourBoard component renders with the wrong geometry. For example, depending on the simulator the Peg size should be 56 but it gets calculated as 7.55.

The second problem is that only the first column in the Grid gets rendered.

These pictures show the initial render, an 8x11 Grid, and the incorrect render after the settings have been applied. It shows a 1x11 Grid which should be 7x11 and the Peg size is way too small.

correct initial renderincorrect render after the settings change

Here is my Colourboard code

import * as React from 'react';
import {View, StyleSheet, Dimensions, StatusBar} from 'react-native';
import {Col, Row, Grid} from 'react-native-easy-grid';
import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
import Peg from './Peg';
import {useSelector} from 'react-redux';

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

export function ColourBoard() {
  const numPosInCode = useSelector(store => store.gameplay.numPosInCode);
  const numColours = useSelector(store => store.gameplay.numColours);
  const numMoves = useSelector(store => store.gameplay.numMoves);
  const tabBarHeight = useBottomTabBarHeight();
  const usableHeight = height - tabBarHeight - StatusBar.currentHeight;
  console.log(`numPosInCode: ${numPosInCode}`);
  console.log(`numColours: ${numColours}`);
  console.log(`numMoves: ${numMoves}`);
  console.log(`width: ${width}`);
  console.log(`width / (numPosInCode + 2): ${width / (numPosInCode + 2)}`);
  const pegSize = width / (numPosInCode + 2) - 2;
  console.log(`pegSize: ${pegSize}`);
  const top = (usableHeight / (numMoves + 1) - pegSize) / 2;

  return (
    <View
      style={[
        styles.MainContainer,
        {
          top: top,
        },
      ]}>
      <Grid>
        {[...Array(numPosInCode + 2)].map((x, i) => (
          <Col>
            {[...Array(numMoves + 1)].map((x, i) => (
              <Row>
                <Peg pegSize={pegSize} key={i} />
              </Row>
            ))}
          </Col>
        ))}
      </Grid>
    </View>
  );
}

const styles = StyleSheet.create({
  MainContainer: {
    left: 1,
    justifyContent: 'center',
    alignItems: 'center',
    height: '100%',
    width: '100%',
    position: 'absolute',
    zIndex: 1,
  },
});

And the entire project is here: http://sendanywhe.re/WEEG3AS7

I am new to React Native but I assume the Colourboard is rendered too quickly, without waiting for the Redux data to update? Any help would be great.

Upvotes: 1

Views: 148

Answers (1)

caslawter
caslawter

Reputation: 662

The problem was because of your numPosInCode. In Javascript, when you add a number to a string or a string to a number, the result is a string. In this case when you did numPosInCode + 2, it becomes 52. What you need to do is to convert the string to a number with the parseInt function.

Heres the fixed code.

import * as React from 'react';
import {View, StyleSheet, Dimensions, StatusBar} from 'react-native';
import {Col, Row, Grid} from 'react-native-easy-grid';
import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
import Peg from './Peg';
import {useSelector} from 'react-redux';

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

export function ColourBoard() {
  const numPosInCode = parseInt(useSelector(store => store.gameplay.numPosInCode));
  const numColours = useSelector(store => store.gameplay.numColours);
  const numMoves = parseInt(useSelector(store => store.gameplay.numMoves));
  const tabBarHeight = useBottomTabBarHeight();
  const usableHeight = height - tabBarHeight - StatusBar.currentHeight;
  console.log(`numPosInCode: ${numPosInCode}`);
  console.log(`numColours: ${numColours}`);
  console.log(`numMoves: ${numMoves}`);
  console.log(`width: ${width}`);
  console.log(`width / (numPosInCode + 2): ${width / (numPosInCode + 2)}`);
  const pegSize = width / (numPosInCode + 2) - 2;
  console.log(`pegSize: ${pegSize}`);
  const top = (usableHeight / (numMoves + 1) - pegSize) / 2;

  return (
    <View
      style={[
        styles.MainContainer,
        {
          top: top,
        },
      ]}>
      <Grid>
        {[...Array(numPosInCode + 2)].map((x, i) => (
          <Col>
            {[...Array(numMoves + 1)].map((x, i) => (
              <Row>
                <Peg pegSize={pegSize} key={i} />
              </Row>
            ))}
          </Col>
        ))}
      </Grid>
    </View>
  );
}

const styles = StyleSheet.create({
  MainContainer: {
    left: 1,
    justifyContent: 'center',
    alignItems: 'center',
    height: '100%',
    width: '100%',
    position: 'absolute',
    zIndex: 1,
  },
});

Upvotes: 1

Related Questions