Joaquin Palacios
Joaquin Palacios

Reputation: 346

React Typescript hooks and props

This is my first project using Typescript and also React Native. I just create a simple logic on App.tsx then, I tried to split it with a component. But, when I pass the props from the Modal component I get an error ts(2322). I know the code needs to be improve as it is my first time using Typescript. I do not know if someone could help me guiding me about it. Below is the original App.tsx I did:

import { Button, FlatList, Modal, StyleSheet, Text, TextInput, View } from 'react-native';

import React from 'react';
import { useState } from 'react';

export interface AppProps {
  id: string | number;
  item: string;
  name: string;
  placeholder: string;
  value: string
}
 
const App: React.FC<AppProps> = () => {
  const [textInput, setTextInput] = useState<string>('');
  const [itemList, setItemList] = useState<any[]>([]);

  const [itemSelected, setItemSelected] = useState<any>({});
  const [modalVisible, setModalVisible] = useState<boolean>(false);

  const handlerConfirmDelete = () => {
    setItemList(itemList.filter(item => item.id !== itemSelected.id));
    setItemSelected({});
    setModalVisible(false);
  }

  const handlerModalOpen = (id: string) => {
    setItemSelected(itemList.find(item => item.id === id));
    setModalVisible(true);
  }

  const onHandlerChangeText = (textValue: string) => setTextInput(textValue);
  const handleAddPress = () => {
    setItemList([
      ...itemList,
      {
        id: Math.random().toString(),
        value: textInput,
      },
    ]);
  }
  return (
    <>
    <View style={styles.container}>
      <View style={styles.firstInputs}>        
        <TextInput placeholder='Item de Lista'
        onChangeText={onHandlerChangeText}
        value={textInput} />
        <Button title='Add' onPress={handleAddPress} />
      </View>
      <View>
        <FlatList
        data={itemList}
        keyExtractor={(item) => item.id}
        renderItem={(data) => (
          <View>          
            <Text>{data.item.value}</Text>  
            <Button title='X' onPress={() => handlerModalOpen(data.item.id)} />        
          </View>
        )}      
        />
      </View>   
    </View>
    <Modal animationType='slide' visible={modalVisible}>
      <View>
        <Text>Borrar</Text>
      </View>
      <View>
        <Text>seguro q borramos?</Text>
      </View>
      <View>
        <Text>{itemSelected.value}</Text>
      </View>
      <View>
        <Button onPress={handlerConfirmDelete} title='Confirm' />
      </View>
    </Modal>
    </>
  );
}

export default App;

This is the new App.tsx and the Modal.tsx: App.tsx

import { Button, FlatList, Modal, StyleSheet, Text, TextInput, View } from 'react-native';

import ModalComponent from './components/Modal';
import React from 'react';
import { useState } from 'react';

export interface AppProps {
  id: string | number;
  item: string;
  name: string;
  placeholder: string;
  value: string
}
 
const App: React.FC<AppProps> = () => {
  const [textInput, setTextInput] = useState<string>('');
  const [itemList, setItemList] = useState<any[]>([]);

  const [itemSelected, setItemSelected] = useState<any>({});
  const [modalVisible, setModalVisible] = useState<boolean>(false);

  const handlerConfirmDelete = () => {
    setItemList(itemList.filter(item => item.id !== itemSelected.id));
    setItemSelected({});
    setModalVisible(false);
  }

  const handlerModalOpen = (id: string) => {
    setItemSelected(itemList.find(item => item.id === id));
    setModalVisible(true);
  }

  const onHandlerChangeText = (textValue: string) => setTextInput(textValue);
  const handleAddPress = () => {
    setItemList([
      ...itemList,
      {
        id: Math.random().toString(),
        value: textInput,
      },
    ]);
  }
  return (
    <>
    <View style={styles.container}>
      <View style={styles.firstInputs}>        
        <TextInput placeholder='Item de Lista'
        onChangeText={onHandlerChangeText}
        value={textInput} />
        <Button title='Add' onPress={handleAddPress} />
      </View>
      <View>
        <FlatList
        data={itemList}
        keyExtractor={(item) => item.id}
        renderItem={(data) => (
          <View>          
            <Text>{data.item.value}</Text>  
            <Button title='X' onPress={() => handlerModalOpen(data.item.id)} />        
          </View>
        )}      
        />
      </View>   
    </View>
    <ModalComponent modalVisible={modalVisible} itemSelected={itemSelected} handlerConfirmDelete={handlerConfirmDelete} />
    </>
  );
}

export default App;

Modal.tsx

import { Button, Modal, StyleSheet, Text, View } from "react-native";

import { AppProps } from "../../App";

export interface ModalComponentProps {
    props: AppProps
    
}
 
const ModalComponent: React.FC<ModalComponentProps> = (props: any) => {
    
    const {modalVisible, itemSelected, handlerConfirmDelete} = props;
    return (
        <>
            <Modal animationType='slide' visible={modalVisible}>
                <View style={styles.modalContainer}>           
                    <View style={[styles.modalContent, styles.shadow]}>
                        <Text style={styles.modalMessage}>Seguro deseas borrar?</Text>
                        <Text style={styles.modalTitle}>{itemSelected.value}</Text>                    
                        <View>
                            <Button onPress={handlerConfirmDelete} title='Confirm' />
                        </View>
                    </View>
                </View>
            </Modal>
        </>
    );
}
export default ModalComponent;

I haven't put the styles yet as I want first to make it work correctly. Thanks in advance.

This is the error: Type '{ modalVisible: boolean; itemSelected: any; handlerConfirmDelete: () => void; }' is not assignable to type 'IntrinsicAttributes & ModalComponentProps & { children?: ReactNode; }'. Property 'modalVisible' does not exist on type 'IntrinsicAttributes & ModalComponentProps & { children?: ReactNode; }'.

Upvotes: 0

Views: 2061

Answers (1)

tsamridh86
tsamridh86

Reputation: 1496

Some basics here:

  1. If you use React.FC<DataType>, the DataType is automatically applied to the props of the component, but you have done props:any in ModalComponent, this would have bypassed the compile issue, but it would break things later on. So, change props:any to just props.

Tip: Just hover over props in VSCode, it's intellisense will show you it's datatype

  1. You are using AppProps in App.tsx as React.FC<AppProps>, if you change it to const App: React.FC<AppProps> = (props) => {...}, and hover over props again, you can see the intellisense doing it's magic, but since it's not used anywhere in the code, you can remove it.

Now on to the core problem, if you hover over props you can see what it contains, it will only contain props: AppProps which isn't used anywhere in your code.

Instead change it to :

interface ModalComponentProps {
   modalVisible: boolean
   itemSelected: any // you have set any in App.tsx
   handlerConfirmDelete: () => void
    
}

and it should work. I still think you will have issue with styles as I don't know where it is imported from. 🙂

I would recommend to use object instead of any, or a custom interface over object. any will make things easy for now and bite you later.

Upvotes: 2

Related Questions