使用钩子将类组件转换为功能组件

时间:2020-07-16 07:17:04

标签: javascript reactjs react-native

我试图转换下面的类组件代码:

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

此功能组件代码:

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

但是,我得到的结果是空白。该表未显示。我尝试在console.log(fetchData())函数内进行useEffect,并在控制台中打印了此结果Promise {<pending>}。这是什么意思?为什么表格未按原样显示?预先非常感谢。

3 个答案:

答案 0 :(得分:0)

您要从setVoter中的fetchVoter函数返回useEffect,这就是控制台打印承诺的原因。

您应该尝试这样

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

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

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

答案 1 :(得分:0)

是什么意思?

Promise {<pending>}告诉您该函数的结果是尚未解决的承诺。 An async function will return a Promise when invoked without await;

如果要查看网络请求的内容,则应在console.log函数中fetchData

为什么表格未按原样显示?

我认为是因为您没有正确设置getAllVoters结果。

在原始代码中,将API结果中的状态变量voters设置为data.data,而在重构后的代码中,您可以使用以下方法将其简单地设置为结果:

setVoters(await api.getAllVoters())

您可以将其更改为:

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

    fetchData()
}, [])

值得一提的是您使用的useState错误。

您正在这样使用它:

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

它应该像这样使用:

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

此刻,您正在将变量isLoading设置为以下对象:{isLoading: false},而您只想将其设置为false。

当您立即使用setIsLoading(true)将值更改为true时,这不会给您造成问题,但是,这很可能会导致错误。

useState ({voters: []})也是如此。

答案 2 :(得分:0)

我相信您没有有效地使用useEffect挂钩。我在您的代码中看到的问题很少,其中一个是将async与一个函数配合使用(正确),但是async-await的规则是当您拥有async函数时无论您叫到哪里,都必须await。 同样好的做法是将api逻辑放在useEffect之外的单独函数中。 我在您的代码中发现的另一个问题是您的isLoading状态被初始化为对象,但是在您的fetctData函数中将其设置为bool值是错误的。您可以简单地将其初始化为true并在获取数据后将其设置为false 因此,您上面VotersList的组件代码将类似于以下内容

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>
        )
    
}