Skip to main content

React Native Hooks

Victoria Harbour, Hongkong

Github Repository

Setup

npm install -g expo-cli
expo init react-native-hooks

Choose the blank template and run the client:

cd react-native-hooks
npm install styled-components
npm start

I can test code by scanning the QR Code using the Expo Go app under Android or by pressing the w key to activate a web preview.

error:0308010C:digital envelope routines::unsupported: Newer versions of Node.js use OpenSSLv3 that brought some breaking changes. Can be fixed (>=Nodejs v17) by adding the following option to the start script inside your package.json -> "start": "export NODE_OPTIONS=--openssl-legacy-provider && expo start"

useState Hook in Functional Components

The useState function allows us to access state in functional components. In a previous example we used state in a class component to add items to a React Native FlatList. Here is how this would look like in a functional component:

import React, {useState} from 'react'
import { View, Text } from 'react-native'
import { v4 as uuidv4 } from 'uuid';

import { StyledList, ListButton, ListButtonTitle } from './_styles'

const ToDoList = () => {

    const [todos, setTodos] = useState([
        {text: 'Qué tengas un lindo día!', id: `${uuidv4()}`},
    ])

    const addTodo = () => {
        setTodos([...todos, {text: '¡Y otra cosa que hacer!', id: `${uuidv4()}`}])
    }

    return (
        <View>
            <StyledList 
                data={todos}
                keyExtractor={(todo) => todo.id}
                renderItem={ ({ item }) => {
                    return (
                        <Text>{item.text}</Text>
                    )
                }}
            />
            <ListButton onPress={addTodo}>
                <ListButtonTitle>Añadir artículo</ListButtonTitle>
            </ListButton>
        </View>
    )
}

export default ToDoList

Working with Form Data

Instead of adding some hard coded text we can now create an input field and use the user input to add new items to our list. This will be done in a component AddToDo that will feed the user input into our addTodo function:

import React, {useState} from 'react'
import { View, Text } from 'react-native'
import { v4 as uuidv4 } from 'uuid';

import { StyledList } from './_styles'
import AddToDo from './AddToDo';

const ToDoList = () => {

    const [todos, setTodos] = useState([
        {text: 'Qué tengas un lindo día!', id: `${uuidv4()}`},
    ])

    const addTodo = (text) => {
        setTodos([...todos, { text, id: `${uuidv4()}`}])
    }

    return (
        <View>
            <StyledList 
                data={todos}
                keyExtractor={(todo) => todo.id}
                renderItem={ ({ item }) => {
                    return (
                        <Text>{item.text}</Text>
                    )
                }}
            />
            <AddToDo addTodo={addTodo} />
        </View>
    )
}

export default ToDoList
import React, {useState} from 'react'

import {StyledTextInput, ListButton, ListButtonTitle, FormContainer, FormHeader } from './_styles'

const AddToDo = ({addTodo}) => {

    const [input, setTodo] = useState('')

    const onButtonPress = () => {
        // Push input from state to parent component to add to list
        addTodo(input)
        // Clean input field once done
        setTodo('')
    }

    return (
        <FormContainer>
	            <FormHeader>Agregar un nuevo elemento de tareas pendientes:</FormHeader>
            <StyledTextInput 
                // set value of field to it's content
                value={input}
                // update state with the user input text
                onChangeText={(text) => setTodo(text)}
            />
            <ListButton onPress={onButtonPress} >
                <ListButtonTitle>Añadir artículo</ListButtonTitle>
            </ListButton>
        </FormContainer>
    )
}

export default AddToDo

useEffect Hook in Functional Components

useEffect replaces the life cycle function that allows you to run functions every time a component renders:

useEffect (() => {
        console.log('useEffect', todos)
    })

We can limit the function to only run when a certain value changes, e.g. :

useEffect (() => {
        console.log('useEffect', todos)
    }, [todos])