bfrizb
bfrizb

Reputation: 113

`useState` erroneously links multiple instances of a single Redux + React Native Component

Context

I've created a custom React Native Text component that I call TextInputSetting, which should update the redux state as a user enters text into it.

The component works fine if I use it just once, but as soon as I try to reuse it, I run into problems (see GIF below to see what I mean).

In experimenting, I found that if I duplicate the component definition (i.e. create TextInputSetting2), I run into the same problem. However, if I duplicate the component and use different variables names for the results of the call to useState (i.e. tempText2 & setTempText2 in one component definition and tempText & setTempText in the other), only then the component instances will function as expected.

Question

Why can't I invoke useState in a reusable React Native + Redux component, and have it work as expected?

Details

enter image description here

TextInputSetting.js

import React, { useState } from "react";
import { Text, TextInput, View } from "react-native";
import { useDispatch, useSelector } from "react-redux";
import { updateSetting } from "./actions";

export const TextInputSetting = (props) => {
  const settings = useSelector((state) => state.settingsReducer);
  const dispatch = useDispatch();
  [tempText, setTempText] = useState(settings[props.settingKey]);

  return (
    <View style={[{ paddingLeft: 50, marginTop: 5, flexDirection: "row" }]}>
      <Text>{props.label}:</Text>
      <TextInput
        value={tempText}
        style={{
          backgroundColor: "yellow",
          borderWidth: 1,
          width: props.boxWidth,
          textAlign: "center",
        }}
        onChangeText={(text) => setTempText(text)}
        onEndEditing={() => dispatch(updateSetting(props.settingKey, tempText))}
      />
    </View>
  );
};

actions.js

export const UPDATE_STATE = "UPDATE_STATE";

export const updateSetting = (k, v) => (dispatch) => {
  dispatch({
    type: UPDATE_STATE,
    payload: { key: k, value: v },
  });
};

reducers.js

import { UPDATE_STATE } from "./actions";

const defaultSettings = {
  set1: "default1",
  set2: "default2",
};

export const settingsReducer = (state = defaultSettings, action) => {
  switch (action.type) {
    case UPDATE_STATE:
      return { ...state, [action.payload.key]: action.payload.value };
    default:
      return state;
  }
};

App.js

import React from "react";
import { Text } from "react-native";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { persistor, store } from "./store";
import { TextInputSetting } from "./TextInputSetting";

export default function App() {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <>
          <Text style={{ fontSize: 50, textAlign: "center", paddingTop: 200 }}>
            Hi there
          </Text>
          <TextInputSetting
            label="First Field"
            settingKey="set1"
            boxWidth={200}
          />
          <TextInputSetting
            label="Second Field"
            settingKey="set2"
            boxWidth={200}
          />
        </>
      </PersistGate>
    </Provider>
  );
}

Code

You can run the code for yourself; I've zipped the full example here (less than 1 MB): https://drive.google.com/file/d/1FJ5AGXlT680uvHIjKxaZUEwliW79_MmT/view?usp=sharing

Upvotes: 1

Views: 55

Answers (1)

Arun Kumar Mohan
Arun Kumar Mohan

Reputation: 11915

The issue is on this line.

[tempText, setTempText] = useState(settings[props.settingKey]);

It should be

const [tempText, setTempText] = useState(settings[props.settingKey]);

Expo Snack

Upvotes: 1

Related Questions