简体   繁体   English

使用 Hooks 将 Class 组件转换为功能组件

[英]Converting Class Component to Functional Component With Hooks

I tried to convert the class component code below:我尝试在下面转换 class 组件代码:

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.我尝试在useEffect function 中使用console.log(fetchData()) ,并在控制台中打印了这个结果Promise {<pending>} 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.您从fetchVoter内部的useEffect setVoter这就是控制台打印 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. Promise {<pending>}告诉您 function 的结果是尚未解决的 promise。 An async function will return a Promise when invoked without await ; async function 将在没有await的情况下调用 Promise

If you want to view the contents of your network request you should console.log within your fetchData function.如果您想查看网络请求的内容,您应该在fetchData function 中使用console.log

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.我认为这是因为您没有正确设置getAllVoters结果。

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:在您的原始代码中,您将 state 变量voters设置为来自 API 结果的data.data ,而在重构代码中,您只需将其设置为结果:

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.还值得一提的是,您错误地使用useState

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.目前,您正在将变量isLoading设置为此 object: {isLoading: false}而您只是想将其设置为 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.目前这不会给您带来问题,因为您会立即使用setIsLoading(true)将值更改为 true,但是,它可能会导致错误。

The same is true for useState ({voters: []}) . useState ({voters: []})也是如此。

I believe you're not using useEffect hook effectively.我相信你没有有效地使用useEffect钩子。 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.我在您的代码中看到的问题很少,其中一个是将async与函数一起使用(这是正确的),但async-await的规则是,当您有async function 时,无论您调用它,您都必须await Also the good practice is to put your api logic outside useEffect in a separate function.此外,好的做法是将您的 api 逻辑放在useEffect之外,放在单独的 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.我在您的代码中发现的另一个问题是您的isLoading state 被初始化为 object 但随后在您的fetctData function 值中您设置错误。 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您可以简单地将其初始化为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>
        )
    
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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