Search code examples
javascriptreactjstypescriptreact-nativenative-base

move textInput element to a separate component


I have a screen where I use this :

const [searchText, setSearchText] = useState('');

          <Item rounded style={styles.inputItem}>
            <Icon
              name="search"
              size={moderateScale(18)}
              color="#bdbdbd"
              style={styles.icon}
            />
            <Input
              autoFocus={true}
              autoCapitalize="none"
              style={styles.inputField}
              placeholder="Friend Search"
              keyboardType="default"
              onChangeText={(text: string) => {
                setSearchText(text);
              }}
            />
          </Item>

Instead of using the Input element on my current screen, I want to turn it into a reusable component. Something like this:

type SearchInputProps = {
  handleChange?: any;
};

export const SearchInput: React.FunctionComponent<SearchInputProps> = (handleChange) => {
  return (
    <Item rounded style={styles.inputItem}>
      <Icon name='search' size={moderateScale(18)} color="#bdbdbd" style={styles.icon}/>
      <Input
        autoFocus={true}
        autoCapitalize="none"
        style={styles.inputField}
        placeholder="Friend Search"
        onChangeText={()=>handleChange}
      />
    </Item>
  );
};

However, I am unable to figure out how to make the onChangeText work such that the const [searchText, setSearchText] = useState(''); value from the main screen can be set over there. Is it even possible?

I tried to create a snack expo here but I am unable to install native base https://snack.expo.io/@nhammad/curious-bubblegum

Edit: Managed to resolve the type error but still don't know how to pass setSearchText while calling the component.

type SearchInputProps = React.PropsWithRef<{
  handleChange?: any;
}>;
export const FieldInput = React.forwardRef<Input, SearchInputProps>(
  ({ handleChange }) => {
    return (
      <Item rounded style={styles.inputItem}>
        <Icon
          name="search"
          size={moderateScale(18)}
          color="#bdbdbd"
          style={styles.icon}
        />
        <Input
          autoFocus={true}
          autoCapitalize="none"
          style={styles.inputField}
          placeholder="Friend Search"
          keyboardType="default"
          onChangeText={handleChange}
        />
      </Item>
    );
  },
);

Solution

  • You can create a reusable Input component by containing common behavior inside the component and then exposing the APIs to consumer component through props. Here is a Snack example. Please check the Input component inside components folder.

    import React, {useState} from 'react';
    import { StyleSheet, Text, TextInput as RnTextInput, View } from 'react-native';
    
    const Input = ({label, onFocus, ...rest}) => {
      const [isFocussed, setIsFocussed] = useState(false);
    
      const handleFocus = () => {
        setIsFocussed(true);
        onFocus && onFocus();
      };
    
      return (
        <View style={[styles.container, isFocussed && styles.inputFocused]}>
          <Text style={styles.label}>{label}</Text>
          <RnTextInput
            style={styles.input}
            onFocus={handleFocus}
            {...rest}
          />
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      container: {
        margin: 5,
        borderBottomWidth: 1,
        borderBottomColor: '#d3d3d3',
      },
      label: {
        color: 'red',
      },
      input: {
        height: 40,
        fontSize: 16,
        paddingLeft: 10,
      },
      inputFocused: {
        borderBottomColor: 'blue'
      }
    })
    
    export default Input;
    

    Then use the component like this:

    <Input
      label="Enter Name"
      onChangeText={text => onChangeText(text)}
      onFocus={handleOnFocus}
      placeholder="Enter some value"
      value={value}
    />
    

    Note: I have used React Native inbuilt TextInput but as per my initial impression native-base's Input has same API as RN TextInput.