简体   繁体   中英

Converting Class Component to Functional Component With Hooks

I tried to convert the class component code below:

import React, { Component } from 'react'
import ReactTable from 'react-table'
import api from '../api'

import styled from 'styled-components'

import 'react-table/react-table.css'

const Wrapper = styled.div`
    padding: 0 40px 40px 40px;
`

const Update = styled.div`  
    color: #ef9b0f;
    cursor: pointer;
`

const Delete = styled.div`
    color: #ff0000;
    cursor: pointer;
`

class UpdateVoter extends Component {
    updateUser = event => {
        event.preventDefault()

        window.location.href = `/voters/update/${this.props.id}`
    }

    render() {
        return <Update onClick={this.updateUser}>Update</Update>
    }
}

class DeleteVoter extends Component {
    deleteUser = event => {
        event.preventDefault()

        if (
            window.confirm(
                `Do you want to delete this voter ${this.props.id} permanently?`,
            )
        ) {
            api.deleteVoterById(this.props.id)
            window.location.reload()
        }
    }

    render() {
        return <Delete onClick={this.deleteUser}>Delete</Delete>
    }
}

class VotersList extends Component {
    constructor(props) {
        super(props)
        this.state = {
            voters: [],
            columns: [],
            isLoading: false,
        }
    }

    componentDidMount = async () => {
        this.setState({ isLoading: true })

        await api.getAllVoters().then(voters => {
            this.setState({
                voters: voters.data.data,
                isLoading: false,
            })
        })
    }

    render() {
        //const { voters, isLoading } = this.state

        const columns = [
            {
                Header: 'ID',
                accessor: '_id',
                filterable: true,
            },
            {
                Header: 'No KK',
                accessor: 'nkk',
                filterable: true,
            },
            {
                Header: 'NIK',
                accessor: 'nik',
                filterable: true,
            },
            {
                Header: 'Nama',
                accessor: 'nama',
                filterable: true,
            },
            {
                Header: 'Alamat',
                accessor: 'alamat',
                filterable: true,
            },
            {
                Header: '',
                accessor: '',
                Cell: function(props) {
                    return (
                        <span>
                            <DeleteVoter id={props.original._id} />
                        </span>
                    )
                },
            },
            {
                Header: '',
                accessor: '',
                Cell: function(props) {
                    return (
                        <span>
                            <UpdateVoter id={props.original._id} />
                        </span>
                    )
                },
            },
        ]

        let showTable = true
        if (!this.state.voters.length) {
            showTable = false
        }

        return (
            <Wrapper>
                {showTable && (
                    <ReactTable
                        data={this.state.voters}
                        columns={columns}
                        loading={this.state.isLoading}
                        defaultPageSize={10}
                        showPageSizeOptions={true}
                        minRows={0}
                    />
                )}
            </Wrapper>
        )
    }
}

export default VotersList

to this functional component code:

import React, {useState, useEffect} from 'react'
import ReactTable from 'react-table'
import api from '../api'

import styled from 'styled-components'

import 'react-table/react-table.css'

const Wrapper = styled.div`
    padding: 0 40px 40px 40px;
`

const Update = styled.div`
    color: #ef9b0f;
    cursor: pointer;
`

const Delete = styled.div`
    color: #ff0000;
    cursor: pointer;
`

function UpdateVoter(props) {
    const updateUser = event => {
        event.preventDefault()

        window.location.href = `/voters/update/${props.id}`
    }

    
        return <Update onClick={updateUser}>Update</Update>

}

function DeleteVoter(props) {
    const deleteUser = event => {
        event.preventDefault()

        if (
            window.confirm(
                `Do tou want to delete this voter ${props.id} permanently?`,
            )
        ) {
            api.deleteVoterById(props.id)
            window.location.reload()
        }
    }

        return <Delete onClick={deleteUser}>Delete</Delete>
  
}

function VotersList(props) {
    const [voters, setVoters] = useState ({voters: []})
    const [isLoading, setIsLoading] = useState ({isLoading: false})

    useEffect(() => {
        async function fetchData() {
            setIsLoading(true)
            return (setVoters(await api.getAllVoters()))
        }
        console.log(fetchData())
    }, [])

        const columns = [
            {
                Header: 'ID',
                accessor: '_id',
            },
            {
                Header: 'No KK',
                accessor: 'nkk',
            },
            {
                Header: 'NIK',
                accessor: 'nik',
            },
            {
                Header: 'Nama',
                accessor: 'nama',
            },
            {
                Header: 'Alamat',
                accessor: 'alamat',
            },
            {
                Header: '',
                accessor: '',
                Cell: function(props) {
                    return (
                        <span>
                            <DeleteVoter id={props.original._id} />
                        </span>
                    )
                },
            },
            {
                Header: '',
                accessor: '',
                Cell: function(props) {
                    return (
                        <span>
                            <UpdateVoter id={props.original._id} />
                        </span>
                    )
                },
            },
        ]

        let showTable = true
        if (!voters.length) {
            showTable = false
        }

        return (
            <Wrapper>
                {showTable && (
                    <ReactTable
                        data={voters}
                        columns={columns}
                        loading={isLoading}
                        defaultPageSize={10}
                        showPageSizeOptions={true}
                        minRows={0}
                    />
                )}
            </Wrapper>
        )
    
}

export default VotersList

But, I got the blank result. The table is not displayed. I tried to console.log(fetchData()) inside useEffect function, and I got this result Promise {<pending>} printed in the console. What does it mean? And why is the table not displayed as it should be? Thank you very much in advance.

You are returning setVoter from fetchVoter function inside useEffect , that's why console is printing a promise.

You should try like this

async function fetchData() {
  const data = await api.getAllVoters()
  return data
}

async handleDataFetch() {
   setIsLoading(true)
   const data = await fetchData()
   setVoters(data)
   setIsLoading(false)
}

useEffect(() => {
  handleDataFetch()
}, [])

What does it mean?

Promise {<pending>} is telling you that the result of the function is a promise that has not yet resolved. An async function will return a Promise when invoked without await ;

If you want to view the contents of your network request you should console.log within your fetchData function.

And why is the table not displayed as it should be?

I think this is occurring because you are not setting the getAllVoters result correctly.

In your original code you set the state variable voters to data.data from the API result, whereas in the refactored code you simple set it to the result with:

setVoters(await api.getAllVoters())

You could fix this by changing it to:

useEffect(() => {
    async function fetchData() {
        setIsLoading(true)
        const voters = await api.getAllVoters();
        setVoters(voters.data.data)
    }

    fetchData()
}, [])

It is also worth mentioning that you are using useState incorrectly.

You are using it like this:

const [isLoading, setIsLoading] = useState({ isLoading: false });

Whereas it should be used like this:

const [isLoading, setIsLoading] = useState(false);

At the moment you are setting the variable isLoading to this object: {isLoading: false} whereas you simply want to set it to false.

This isn't causing you problems at the moment as you are immediately changing the value to true with setIsLoading(true) , however, it will probably cause bugs down the line.

The same is true for useState ({voters: []}) .

I believe you're not using useEffect hook effectively. There are few problems I've seen in your code one of them is using async with a function(which is correct) but the rule of async-await is that when you have an async function you got to await wherever you call it. Also the good practice is to put your api logic outside useEffect in a separate function. There's one more issue I found in your code is your isLoading state is initialized as an object but then in your fetctData function you're set-ting it as a bool value which is wrong. You can simply initialized it to be true and set it to false after data has been fetched So your above component code of VotersList will look something like this

function VotersList(props) {
    const [voters, setVoters] = useState({voters: []})
    const [isLoading, setIsLoading] = useState(true)
    
    const fetchData = async () => {
      let allVoters = await api.getAllVoters();
      setVoters(allVoters);
      setIsLoading(false);
    }

    useEffect(async () => {
        let allVoters = await api.getAllVoters();
        setVoters(allVoters);
    }, [])
    // OR
    /*
    useEffect(async () => {
        await fetchData();
    }, [])
    */




        const columns = [
            {
                Header: 'ID',
                accessor: '_id',
            },
            {
                Header: 'No KK',
                accessor: 'nkk',
            },
            {
                Header: 'NIK',
                accessor: 'nik',
            },
            {
                Header: 'Nama',
                accessor: 'nama',
            },
            {
                Header: 'Alamat',
                accessor: 'alamat',
            },
            {
                Header: '',
                accessor: '',
                Cell: function(props) {
                    return (
                        <span>
                            <DeleteVoter id={props.original._id} />
                        </span>
                    )
                },
            },
            {
                Header: '',
                accessor: '',
                Cell: function(props) {
                    return (
                        <span>
                            <UpdateVoter id={props.original._id} />
                        </span>
                    )
                },
            },
        ]

        let showTable = true
        if (!voters.length) {
            showTable = false
        }

        return (
            <Wrapper>
                {showTable && (
                    <ReactTable
                        data={voters}
                        columns={columns}
                        loading={isLoading}
                        defaultPageSize={10}
                        showPageSizeOptions={true}
                        minRows={0}
                    />
                )}
            </Wrapper>
        )
    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM