簡體   English   中英

使用 Hook 將 React Class 組件轉換為 Function 組件

[英]Converting React Class component to Function Component With Hook

我嘗試在下面的反應應用程序中轉換 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 (!voters.length) {
            showTable = false
        }

        return (
            <Wrapper>
                {showTable && (
                    <ReactTable
                        data={voters}
                        columns={columns}
                        loading={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 VotersListSpecific(props) {
    const [state, setState] = useState ({
            voters: [],
            columns: [],
            isLoading: false,
        })
   

    useEffect(() => {
        async function fetchData() {
            setState({ ...state, isLoading: true })

            let voters = await api.getAllVoters()
            setState({
                voters: voters.data.data, 
                ...state,
                isLoading: true,
            })
        }
        fetchData()
        console.log(fetc)
    }, [])

        const { voters, isLoading } = state

        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

但是,代碼不起作用。 該表不顯示。 state 中的“voters”數組為空。 除此之外,我還收到了以下警告:

React Hook useEffect 缺少依賴項:'state'。 包括它或刪除依賴數組。 如果您只需要在 'setState' 調用 react-hooks/exhaustive-deps 中需要 'state',您也可以進行功能更新 'setState(s =>...)'

我真的需要幫助來解決這個問題。 先感謝您。

我的建議

首先, useState不像this.state組件中的 this.state。 建議您為每個原語state分配一個useState function。 例如,在您的VotersListSpecific columns voters ,您可以使用以下isLoading

const [voters, setVoters] = useState([])
const [columns, setColumns] = useState([])
const [isLoading, setLoading] = useState(false)

仍然可以使用useReducer進一步優化它,但現在它太離題了。 有興趣可以查看官方文檔

你的問題

現在讓我們來分析一下你做對了什么,做錯了什么。

權利

當您更改 state 時,您使用語法setState({...state, isLoading: true }) ,這是正確的,因為 React 僅在 ZA8CFDE6331BD46EB2AC96F8 的引用更改時切換重新渲染。 如果你使用這樣的東西:

state.isLoading = false
setState(state)

如果 state 的引用在這種情況下沒有改變,所以 React 不會重新渲染。

錯誤

當您調用const { voters, isLoading } = state時, voters變量指向 state 的voters字段,該字段在第一次渲染時是一個空數組。 一段時間后,當新的state與新的voters一起創建時,新的state.voters實際上指向一個新數組。 但是 React 不知道這個變化,因為你已經明確地將voter變量指向原始的空數組,這是舊的state的一個字段。

對此的修復將類似於:

const [voters, setVoters] = useState([])
useEffect(async () => {
  setVoters(await api.getAllVoters())
}, [])
return (
  <ReactTable data={voters}/>
)

另一種方法是使用data={state.voters}

歡迎來到 React 函數式編程。

我沒有你所有的依賴,所以我試圖通過眼睛而不是實際編譯來回答你的問題。

更新 state 時的一粒鹽,而不是這樣做:

setState({
   ...state,
   ...yourstuffhere
})

做這個:

setState(prevState => {
    return {
        ...prevState,
        ...yourstuffhere
    }
});

發生的情況是通過上述操作,您確保您已從以前的 state 更新數據。 請記住, setState是一個異步 function。 除非您這樣做,否則您可能會不小心丟失一些數據。

useEffect(() => {
    async function fetchData() {
        setState(prevState => { 
            return {
                ...prevState, isLoading: true 
            }
        })

        let voters = await api.getAllVoters()
        setState(prevState => {
            return {
                voters: voters.data.data, 
                ...prevState,
                isLoading: true,
            }
        })
    }
    fetchData()
    console.log(fetc)
}, [])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM