Input component is not changing the state value

Asked

Viewed 249 times

1

I have an Input component that is a Textinput Wrapper (React-Native). When I type the value in my Input component and then try to show the value of the variable to which the text should have been assigned, the variable appears with the value it was created, not changing.

// MyInput
import React from 'react';
import { TextInput, Text } from 'react-native';

import styles from './styles';

interface InputProps {
  label: String,
  placeholder: String,
  onChangeText: Function,
  defaultValue?: String,
  value: String,
}

const Input: React.FC<InputProps> = ({ label }: InputProps, ...props) => {
  return (
    <>
      <Text style={styles.label}>{label}</Text>
      <TextInput { ...props } style={styles.input}/>
    </>
  );
}

export default Input;

And the screen where I call the component:

// login
import React, { useState } from 'react';
import Input from '../../components/Input';

import { View, ImageBackground, Text, Image, Alert, Button } from 'react-native';
import styles from './styles';
import BackgroundLogin from '../../assets/images/BackGroundBanner01.png';

interface UserProps {
  email: String,
  password: String,
}

function Login() {
  const [user, setUser] = useState<UserProps> ({email: 'default', password: ''});
  return (
    <ImageBackground source={BackgroundLogin} style={styles.container}>
      <Input value={user.email} onChangeText={(text: String) => setUser({...user, email: text})} label="Email"></Input>
      <Button
      onPress={() => Alert.alert(`${user.email}`)}
      title="Testar"
      />
    </ImageBackground>
  );
}

export default Login;

When I enter "Hello" text in Input, and press the test button, the application returns me "default" which is the initial value that the variable was instantiated.

If I remove the Wrapper and leave Textinput direct, the code works smoothly.

Citation

2 answers

1


Hello, this happened because in your wrapper you stated:

...
const Input: React.FC<InputProps> = ({ label }: InputProps, ...props) => {
...
}

The correct syntax would be:

...
const Input: React.FC<InputProps> = ({ label,  ...props }) => {
...
}

All props received in a component are saved in the first Component argument. Also as you can see I did not declare the props interface again, but if you do not pass Children for this component there is no need to use React.FC because it declares types that you will not use, in this case it would look like this: The correct syntax would be:

...
const Input = ({ label,  ...props }: InputProps) => {
...
}

A curiosity: the second argument may be the context, but it will be undefined, unless you define the contextTypes for the component, thus:

const Input = (props, context) => {
  // esse context geralmente é utilizado junto ao redux-i18n (i18n: seu site estar disponível em vários idiomas)
  return (
   <span>{context.t('alguma-string')}</span>
  )
}

Input.contextTypes = {
    t: PropTypes.func
}

But of course this is not much used due to hook useContext.

I hope I’ve helped!

  • If I do it this way const Input: React.FC<InputProps> = ({ label, ...props }) => { the Textinput component shows this error "No Overload Matches this call.". as shown in this image: https://ibb.co/BKZ2yFz

  • Yes forgot to talk about it, this is a typescript error, you should take the props interface of the Textfield component and extend with its props interface that has the label

1

How did you use the template for coding and on the component TextInput used in your project has defined types that is Readonly<TextInputProps> that in the particular case can be done an extension to put different types the most in your custom component, the clear example is this interface:

interface Props extends Readonly<TextInputProps> {
  label: string;
}

On the interface Props now beyond the properties of the component TextInput referred to in Readonly<TextInputProps> has a label of the kind string (the guy is always with the s lower case, and this differs from the uppercase S) and from this contract a more streamlined model of this component can be created:

import * as React from 'react';
import { TextInput, Text, TextInputProps } from 'react-native';

interface Props extends Readonly<TextInputProps> {
  label: string;
}

const Input: React.FC<Props> = ({label, ...shared}: Props) => {    
  return (
    <>    
      <Text>{label}</Text>
      <TextInput { ...shared } />                  
    </>
  )
}

export default Input;

noting that label is separated from shared separating the properties and this is entirely passed on to the component in specific.

In the use of the component is simpler and readable using only the properties that are mandatory:

<Input label="Input" 
    value={user.email} 
    onChangeText={(text: string) => setUser({...user, email: text})}
/>

and in this case your component will work as it should, because it does not break the type of component properties as was happening.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.