将状态从 useEffect 传递到组件中的函数?

Passing State from useEffect to Function in Component?

我正在尝试从反应组件中的函数访问我的状态,称为 activeCards。我可以在 Use Effect... 中访问它,但如果按下按钮,我只希望函数为 运行。

函数 reorderActiveCardsDown 从状态中获取数组...并对其重新排序...然后将数组放回原处。它在我基于 class 的组件中工作 - 但我无法将它与基于功能的组件一起使用。

我可以 console.log 来自 useEffect 的状态,它工作正常...但是如果我 console.log 来自函数的状态,它是空的。

我想我的问题是 - 在这种情况下我是否使用 useEffect - 将信息传递回新函数?如果我每次都希望函数 运行... 我可以将它放在 useEffect.. 但我只希望它在我按下该按钮时 运行。

谢谢!

useEffect(() => {

    console.log('active cards updated')
    // prints the whole array to the console. 

}, [activeCards])

const reorderActiveCardsDown = () => {
    let oldArray = []
    console.log(activeCards)
        // prints empty array to the console, hence no access to the state yet. 
    oldArray.push(activeCards);
    console.log(oldArray[0])
    const swapPositions = (array, a ,b) => {
        [array[a], array[b]] = [array[b], array[a]]
      }

    swapPositions(oldArray[0], index, index+1);


    setActiveCards(oldArray[0]);
}

这是完整代码 - 该组件从单个 ID 获取我的 api 以获取 ID 数组。它来自函数 FetchIDS()。一旦数组被获取,它就被设置为 cumulativeList 状态。获取的每个 ID 代表一张卡片 - 这样我就可以让用户添加或删除他们想要的卡片。

更新状态 "cumulativeList" 后,我从 useEffect 函数调用 convertIdToCard()。每个 ID 都获取卡信息并将其转换为存储在状态 "activeCards" 中的组件。 convertIdToCard() 获取卡片信息并调用 CreateQuoteCards()。 CreateQuoteCards() 创建要添加到 ActiveCards 列表的组件。在 CreateQuoteCards() 结束时,我更新了 activeCardsList。渲染函数显示列表。

现在用户可以看到每张卡片。每张卡片还通过道具传递一个函数 - moveCardDown()。当用户按下按钮重新排序特定卡片时,moveCardDown() 将重新排序 cumulativeList(将保存到数据库的 ID 列表)。到这里为止。现在 moveCardDown() 调用我遇到问题的函数...reorderActiveCardsDown()。

这是完整的代码!

    import React, { Component, useState, useEffect } from 'react'
import NewCardModal from './SetupCards/NewCardModal';
import BaseCostCard from './SetupCards/BaseCostCard';
import DatePickerCard from './SetupCards/DatePickerCard';
import TimedRateCard from './SetupCards/TimedRateCard';
import TextCard from './SetupCards/TextCard';
import SelectCard from './SetupCards/SelectCard';
import CheckboxCard from './SetupCards/CheckboxCard';
import NumberCard from './SetupCards/NumberCard';
import SliderCard from './SetupCards/SliderCard'
import { Container } from 'reactstrap';

let updateCumulativeList = true;

const AqgSetup2 = (props) => {

    const [ _id, setId ] = useState("5e888116ea81f0eae86517de");
    const [ activeCards, setActiveCards] = useState([]);
    const [ cumulativeList, setCumulativeList] = useState([]);




    const fetchIDS = async () => {
            try {
                const response = await fetch(`/api/autoquotegenerators/5e888116ea81f0eae86517de`);
                const responseData = await response.json();
                setCumulativeList(responseData.quoteGenerator)  
                // console.log(responseData.quoteGenerator) 
            } catch (error) {
                console.error(error);
            }
    }

    useEffect(() => {
            fetchIDS();
            console.log('fetched')
    }, [])

    useEffect(() => {
        if(updateCumulativeList){
            setTimeout( () => {
            convertIdToCard();
            updateCumulativeList = false
            },300)
        }else {
            console.log(updateCumulativeList)
        }
        cumulativeListPut(); 
    }, [cumulativeList]);   

    useEffect(() => {

        console.log('active cards updated')

    }, [activeCards])

    const convertIdToCard = () => {
        const quoteCards = []
        quoteCards.push(cumulativeList.map(id => {return id}))
        const selfMap = async (quoteCards) => {
            if(quoteCards.length > 0){
                try {
                    let card = quoteCards.shift();
                    const response = await fetch(`/api/autoquotegenerators/${card}`);
                    const responseData = await response.json();
                    createQuoteCards(responseData);
                    selfMap(quoteCards);
                } catch (error) {
                    console.error(error);
                }
            }
        }
        selfMap(quoteCards[0]); 
    }

    const createQuoteCards = (quoteCard) => {
        let display = [];
            if(quoteCard.quoteGenerator[0].cardType === "base"){
                display.push(
                    <BaseCostCard id={quoteCard._id} cardTitle={quoteCard.quoteGenerator[0].cardTitle} charge={quoteCard.quoteGenerator[0].charge} deleteCard={deleteCard} moveCardDown={moveCardDown}/>
                );
            }else if(quoteCard.quoteGenerator[0].cardType === "date"){
                display.push(
                    <DatePickerCard id={quoteCard._id} cardTitle={quoteCard.quoteGenerator[0].cardTitle} charge={quoteCard.quoteGenerator[0].charge} advanced={quoteCard.quoteGenerator[0].advanced} sunday={quoteCard.quoteGenerator[0].sunday} monday={quoteCard.quoteGenerator[0].monday} tuesday={quoteCard.quoteGenerator[0].tuesday} wednesday={quoteCard.quoteGenerator[0].wednesday} thursday={quoteCard.quoteGenerator[0].thursday} friday={quoteCard.quoteGenerator[0].friday} saturday={quoteCard.quoteGenerator[0].saturday} deleteCard={deleteCard} moveCardDown={moveCardDown}/>
                );
            }else if(quoteCard.quoteGenerator[0].cardType === "timed"){
                display.push(
                    <TimedRateCard id={quoteCard._id} cardTitle={quoteCard.quoteGenerator[0].cardTitle} charge={quoteCard.quoteGenerator[0].charge} deleteCard={deleteCard} moveCardDown={moveCardDown}/>
                )
            }else if(quoteCard.quoteGenerator[0].cardType === "text"){
                display.push(
                    <TextCard id={quoteCard._id} cardTitle={quoteCard.quoteGenerator[0].cardTitle} charge={quoteCard.quoteGenerator[0].charge} deleteCard={deleteCard} moveCardDown={moveCardDown}/>
                )
            }else if(quoteCard.quoteGenerator[0].cardType === "select"){
                display.push(
                    <SelectCard id={quoteCard._id} cardTitle={quoteCard.quoteGenerator[0].cardTitle} charge={quoteCard.quoteGenerator[0].charge} selectOptions={quoteCard.quoteGenerator[0].selectOptions}deleteCard={deleteCard} moveCardDown={moveCardDown} />
                )
            }else if(quoteCard.quoteGenerator[0].cardType === "check"){
                display.push(
                    <CheckboxCard id={quoteCard._id} cardTitle={quoteCard.quoteGenerator[0].cardTitle} charge={quoteCard.quoteGenerator[0].charge} deleteCard={deleteCard} moveCardDown={moveCardDown}/>
                )
            }else if(quoteCard.quoteGenerator[0].cardType === "number"){
                display.push(
                    <NumberCard id={quoteCard._id} cardTitle={quoteCard.quoteGenerator[0].cardTitle} charge={quoteCard.quoteGenerator[0].charge} deleteCard={deleteCard} moveCardDown={moveCardDown}/>
                )
            }else if(quoteCard.quoteGenerator[0].cardType === "slider"){
                display.push(
                    <SliderCard id={quoteCard._id} cardTitle={quoteCard.quoteGenerator[0].cardTitle} charge={quoteCard.quoteGenerator[0].charge} deleteCard={deleteCard} moveCardDown={moveCardDown}/>
                )
            }

        setActiveCards(activeCards => [...activeCards, display[0]])
    }

    const baseCostCard = (id) => {
        setActiveCards(activeCards => [...activeCards, <BaseCostCard id={id} deleteCard={deleteCard} moveCardDown={moveCardDown}/> ])

        cumulativeListFetch(id);
    }

    const datePickerCard = (id) => {
        setActiveCards(activeCards => [...activeCards, <DatePickerCard id={id} deleteCard={deleteCard} moveCardDown={moveCardDown}/> ])

        cumulativeListFetch(id);

    }

    const timedRateCard = (id) => {
        setActiveCards(activeCards => [...activeCards, <TimedRateCard id={id} deleteCard={deleteCard} moveCardDown={moveCardDown}/> ])

        cumulativeListFetch(id);
    }

    const textCard = (id) =>{
        setActiveCards(activeCards => [...activeCards, <TextCard id={id} deleteCard={deleteCard} moveCardDown={moveCardDown}/> ])

        cumulativeListFetch(id);
    }

    const selectCard = (id) =>{
        setActiveCards(activeCards => [...activeCards, <SelectCard id={id} deleteCard={deleteCard} moveCardDown={moveCardDown} selectOptions={[]} /> ])

        cumulativeListFetch(id);
    }

    const checkboxCard = (id) =>{
        setActiveCards(activeCards => [...activeCards, <CheckboxCard id={id} deleteCard={deleteCard} moveCardDown={moveCardDown}/> ])

        cumulativeListFetch(id);
    }

    const numberCard = (id) => {
        setActiveCards(activeCards => [...activeCards, <NumberCard id={id} deleteCard={deleteCard} moveCardDown={moveCardDown}/> ])

        cumulativeListFetch(id);
    }

    const sliderCard = (id) => {
        setActiveCards(activeCards => [...activeCards, <SliderCard id={id} deleteCard={deleteCard} moveCardDown={moveCardDown}/> ])

        cumulativeListFetch(id);
    }

    const moveCardDown = (id) => {
        let oldArray = []
        oldArray.push(cumulativeList);
        let index = oldArray[0].indexOf(id);
        let newArray = oldArray[0].filter(card => {
            return card !== id;
        });
        newArray.splice(index + 1, 0, id)

        setCumulativeList(newArray)
        reorderActiveCardsDown();
    }



    const displayExtraModal = () => {
        if(activeCards.length > 0){
            return <NewCardModal baseCostCard={baseCostCard} datePickerCard={datePickerCard} timedRateCard={timedRateCard} textCard={textCard} selectCard={selectCard} checkboxCard={checkboxCard} numberCard={numberCard} sliderCard={sliderCard}/>
        }
    }

    const reorderActiveCardsDown = () => {
        let oldArray = []
        console.log(activeCards)
        oldArray.push(activeCards);
        // console.log(oldArray[0])
        // const swapPositions = (array, a ,b) => {
        //     [array[a], array[b]] = [array[b], array[a]]
        //   }

        // swapPositions(oldArray[0], index, index+1);


        // setActiveCards(oldArray[0]);
    }

    const deleteCard = (id) => {
        setCumulativeList(cumulativeList => [...cumulativeList.filter(card => {
            return card !== id
        })])

            removeFromCumulativeList(id);
    }

    const removeFromCumulativeList = () => {
        let quoteGeneratorTemplate = {
            "quoteGenerator": cumulativeList
        }    

        fetch(`/api/autoquotegenerators/${_id}`, {
            method: 'PUT', 
            headers: {
                'Content-Type': 'application/json; charset=UTF-8',
            },
            body: JSON.stringify(quoteGeneratorTemplate),
            })
            .then((response) => response.json())
            .then((data) => {
            console.log('Updated:', data);
            })
            .catch((error) => {
            console.error('Error:', error);
        });
    }

    const makeNumber = () => {
        Math.floor(Math.random()*10000)
    }

    const cumulativeListFetch = (id) => {
            setCumulativeList( cumulativeList => [...cumulativeList, id])
    }

    const cumulativeListPut = () => {

            let quoteGeneratorTemplate = {
                "quoteGenerator": cumulativeList
            }    

            fetch(`/api/autoquotegenerators/${_id}`, {
                method: 'PUT', 
                headers: {
                    'Content-Type': 'application/json; charset=UTF-8',
                },
                body: JSON.stringify(quoteGeneratorTemplate),
                })
                .then((response) => response.json())
                .then((data) => {
                console.log('Updated:', data);
                })
                .catch((error) => {
                console.error('Error:', error);
            });

    }

        return (
            <Container className="d-flex flex-column justify-content-center">
                <NewCardModal baseCostCard={baseCostCard} datePickerCard={datePickerCard} timedRateCard={timedRateCard} textCard={textCard} selectCard={selectCard} checkboxCard={checkboxCard} numberCard={numberCard} sliderCard={sliderCard}/>
                    {activeCards.map(card => {
                            return <div key={makeNumber()}>{card}</div>
                    })}
                    {displayExtraModal()}
            </Container>
        )

}

export default AqgSetup2

你的问题是,你不小心改变了状态。似乎 React 在这种情况下选择不重新渲染您的组件,所以 reorderActiveCardsDown 仍然有旧数据。

此外,您将函数的实例存储在处于状态的组件中,因此函数内部不会有新状态。 (仅 return 重新渲染中的组件)

要解决此问题,您应该使用 updater function,以便始终使用最新状态。

const reorderActiveCardsDown = () => {
    setActiveCards((oldArray) => {
        let newArray = Array.from(oldArray) //create a fresh array from the current one
        console.log(oldArray)
        const swapPositions = (array, a ,b) => {
            [array[a], array[b]] = [array[b], array[a]]
        }

        swapPositions(newArray, index, index+1);

        return newArray
    });
}

如果您根据以前的值设置新状态,您应该始终使用更新程序,因此相应地修改所有其他功能。

你永远不应该在状态中存储组件实例 (f ex <MyComponent myProp={value} />),因为那样的话道具根本不会更新,你最终会遇到奇怪的副作用,就像你在这里遇到的那样。为了避免这种情况,我将 activeCards 替换为 activeCardData,它仅存储 mapQuoteCard 函数所需的数据,该函数会生成最终应渲染的组件实例。

import React, { Component, useState, useEffect } from "react"
import NewCardModal from "./SetupCards/NewCardModal"
import BaseCostCard from "./SetupCards/BaseCostCard"
import DatePickerCard from "./SetupCards/DatePickerCard"
import TimedRateCard from "./SetupCards/TimedRateCard"
import TextCard from "./SetupCards/TextCard"
import SelectCard from "./SetupCards/SelectCard"
import CheckboxCard from "./SetupCards/CheckboxCard"
import NumberCard from "./SetupCards/NumberCard"
import SliderCard from "./SetupCards/SliderCard"
import { Container } from "reactstrap"

let updateCumulativeList = true

const AqgSetup2 = (props) => {
    const [_id, setId] = useState("5e888116ea81f0eae86517de")
    const [activeCardData, setActiveCardData] = useState([])
    const [cumulativeList, setCumulativeList] = useState([])

    const fetchIDS = async () => {
        try {
            const response = await fetch(
                `/api/autoquotegenerators/5e888116ea81f0eae86517de`
            )
            const responseData = await response.json()
            setCumulativeList(responseData.quoteGenerator)
            // console.log(responseData.quoteGenerator)
        } catch (error) {
            console.error(error)
        }
    }

    useEffect(() => {
        fetchIDS()
        console.log("fetched")
    }, [])

    useEffect(() => {
        if (updateCumulativeList) {
            setTimeout(() => {
                convertIdToCard()
                updateCumulativeList = false
            }, 300)
        } else {
            console.log(updateCumulativeList)
        }
        cumulativeListPut()
    }, [cumulativeList])

    useEffect(() => {
        console.log("active cards updated")
    }, [activeCardData])

    const convertIdToCard = () => {
        const quoteCards = []
        quoteCards.push(
            cumulativeList.map((id) => {
                return id
            })
        )
        const selfMap = async (quoteCards) => {
            if (quoteCards.length > 0) {
                try {
                    let card = quoteCards.shift()
                    const response = await fetch(
                        `/api/autoquotegenerators/${card}`
                    )
                    const responseData = await response.json()
                    createQuoteCards(responseData)
                    selfMap(quoteCards)
                } catch (error) {
                    console.error(error)
                }
            }
        }
        selfMap(quoteCards[0])
    }

    const createQuoteCards = (quoteCard) => {
        setActiveCardData((previousTypes) => [...previousTypes, quoteCard])
    }

    const mapQuoteCard = (quoteCard) => {
        switch (quoteCard.quoteGenerator[0].cardType) {
            case "base":
                return (
                    <BaseCostCard
                        id={quoteCard._id}
                        cardTitle={quoteCard.quoteGenerator[0].cardTitle}
                        charge={quoteCard.quoteGenerator[0].charge}
                        deleteCard={deleteCard}
                        moveCardDown={moveCardDown}
                    />
                )
            case "date":
                return (
                    <DatePickerCard
                        id={quoteCard._id}
                        cardTitle={quoteCard.quoteGenerator[0].cardTitle}
                        charge={quoteCard.quoteGenerator[0].charge}
                        advanced={quoteCard.quoteGenerator[0].advanced}
                        sunday={quoteCard.quoteGenerator[0].sunday}
                        monday={quoteCard.quoteGenerator[0].monday}
                        tuesday={quoteCard.quoteGenerator[0].tuesday}
                        wednesday={quoteCard.quoteGenerator[0].wednesday}
                        thursday={quoteCard.quoteGenerator[0].thursday}
                        friday={quoteCard.quoteGenerator[0].friday}
                        saturday={quoteCard.quoteGenerator[0].saturday}
                        deleteCard={deleteCard}
                        moveCardDown={moveCardDown}
                    />
                )
            case "timed":
                return (
                    <TimedRateCard
                        id={quoteCard._id}
                        cardTitle={quoteCard.quoteGenerator[0].cardTitle}
                        charge={quoteCard.quoteGenerator[0].charge}
                        deleteCard={deleteCard}
                        moveCardDown={moveCardDown}
                    />
                )
            case "text":
                return (
                    <TextCard
                        id={quoteCard._id}
                        cardTitle={quoteCard.quoteGenerator[0].cardTitle}
                        charge={quoteCard.quoteGenerator[0].charge}
                        deleteCard={deleteCard}
                        moveCardDown={moveCardDown}
                    />
                )
            case "select":
                return (
                    <SelectCard
                        id={quoteCard._id}
                        cardTitle={quoteCard.quoteGenerator[0].cardTitle}
                        charge={quoteCard.quoteGenerator[0].charge}
                        selectOptions={
                            quoteCard.quoteGenerator[0].selectOptions
                        }
                        deleteCard={deleteCard}
                        moveCardDown={moveCardDown}
                    />
                )
            case "check":
                return (
                    <CheckboxCard
                        id={quoteCard._id}
                        cardTitle={quoteCard.quoteGenerator[0].cardTitle}
                        charge={quoteCard.quoteGenerator[0].charge}
                        deleteCard={deleteCard}
                        moveCardDown={moveCardDown}
                    />
                )
            case "number":
                return (
                    <NumberCard
                        id={quoteCard._id}
                        cardTitle={quoteCard.quoteGenerator[0].cardTitle}
                        charge={quoteCard.quoteGenerator[0].charge}
                        deleteCard={deleteCard}
                        moveCardDown={moveCardDown}
                    />
                )
            case "slider":
                return (
                    <SliderCard
                        id={quoteCard._id}
                        cardTitle={quoteCard.quoteGenerator[0].cardTitle}
                        charge={quoteCard.quoteGenerator[0].charge}
                        deleteCard={deleteCard}
                        moveCardDown={moveCardDown}
                    />
                )
            default:
                return null
        }
    }

    const baseCostCard = (id) => {
        setActiveCardData((activeCards) => [
            ...activeCards,
            {
                _id: id,
                quoteGenerator: [
                    {
                        cardType: "base",
                    },
                ],
            },
        ])

        cumulativeListFetch(id)
    }

    const datePickerCard = (id) => {
        setActiveCardData((activeCards) => [
            ...activeCards,
            {
                _id: id,
                quoteGenerator: [
                    {
                        cardType: "date",
                    },
                ],
            },
        ])

        cumulativeListFetch(id)
    }

    const timedRateCard = (id) => {
        setActiveCardData((activeCards) => [
            ...activeCards,
            {
                _id: id,
                quoteGenerator: [
                    {
                        cardType: "timed",
                    },
                ],
            },
        ])

        cumulativeListFetch(id)
    }

    const textCard = (id) => {
        setActiveCardData((activeCards) => [
            ...activeCards,
            {
                _id: id,
                quoteGenerator: [
                    {
                        cardType: "text",
                    },
                ],
            },
        ])

        cumulativeListFetch(id)
    }

    const selectCard = (id) => {
        setActiveCardData((activeCards) => [
            ...activeCards,
            {
                _id: id,
                quoteGenerator: [
                    {
                        cardType: "select",
                        selectOptions: [],
                    },
                ],
            },
        ])

        cumulativeListFetch(id)
    }

    const checkboxCard = (id) => {
        setActiveCardData((activeCards) => [
            ...activeCards,
            {
                _id: id,
                quoteGenerator: [
                    {
                        cardType: "check",
                    },
                ],
            },
        ])

        cumulativeListFetch(id)
    }

    const numberCard = (id) => {
        setActiveCardData((activeCards) => [
            ...activeCards,
            {
                _id: id,
                quoteGenerator: [
                    {
                        cardType: "number",
                    },
                ],
            },
        ])

        cumulativeListFetch(id)
    }

    const sliderCard = (id) => {
        setActiveCardData((activeCards) => [
            ...activeCards,
            {
                _id: id,
                quoteGenerator: [
                    {
                        cardType: "slider",
                    },
                ],
            },
        ])

        cumulativeListFetch(id)
    }

    const moveCardDown = (id) => {
        let oldArray = []
        oldArray.push(cumulativeList)
        let index = oldArray[0].indexOf(id)
        let newArray = oldArray[0].filter((card) => {
            return card !== id
        })
        newArray.splice(index + 1, 0, id)

        setCumulativeList(newArray)
        reorderActiveCardsDown(index)
    }

    const displayExtraModal = () => {
        if (activeCardData.length > 0) {
            return (
                <NewCardModal
                    baseCostCard={baseCostCard}
                    datePickerCard={datePickerCard}
                    timedRateCard={timedRateCard}
                    textCard={textCard}
                    selectCard={selectCard}
                    checkboxCard={checkboxCard}
                    numberCard={numberCard}
                    sliderCard={sliderCard}
                />
            )
        }
    }

    const reorderActiveCardsDown = (index) => {
        setActiveCardData((oldArray) => {
            let newArray = Array.from(oldArray) //create a fresh array from the current one
            console.log(oldArray)
            const swapPositions = (array, a, b) => {
                ;[array[a], array[b]] = [array[b], array[a]]
            }

            swapPositions(newArray, index, index + 1)

            return newArray
        })
    }

    const deleteCard = (id) => {
        setCumulativeList((cumulativeList) => [
            ...cumulativeList.filter((card) => {
                return card !== id
            }),
        ])

        removeFromCumulativeList(id)
    }

    const removeFromCumulativeList = () => {
        let quoteGeneratorTemplate = {
            quoteGenerator: cumulativeList,
        }

        fetch(`/api/autoquotegenerators/${_id}`, {
            method: "PUT",
            headers: {
                "Content-Type": "application/json; charset=UTF-8",
            },
            body: JSON.stringify(quoteGeneratorTemplate),
        })
            .then((response) => response.json())
            .then((data) => {
                console.log("Updated:", data)
            })
            .catch((error) => {
                console.error("Error:", error)
            })
    }

    const makeNumber = () => {
        Math.floor(Math.random() * 10000)
    }

    const cumulativeListFetch = (id) => {
        setCumulativeList((cumulativeList) => [...cumulativeList, id])
    }

    const cumulativeListPut = () => {
        let quoteGeneratorTemplate = {
            quoteGenerator: cumulativeList,
        }

        fetch(`/api/autoquotegenerators/${_id}`, {
            method: "PUT",
            headers: {
                "Content-Type": "application/json; charset=UTF-8",
            },
            body: JSON.stringify(quoteGeneratorTemplate),
        })
            .then((response) => response.json())
            .then((data) => {
                console.log("Updated:", data)
            })
            .catch((error) => {
                console.error("Error:", error)
            })
    }

    return (
        <Container className="d-flex flex-column justify-content-center">
            <NewCardModal
                baseCostCard={baseCostCard}
                datePickerCard={datePickerCard}
                timedRateCard={timedRateCard}
                textCard={textCard}
                selectCard={selectCard}
                checkboxCard={checkboxCard}
                numberCard={numberCard}
                sliderCard={sliderCard}
            />
            {activeCardData.map((card) => {
                const currCard = mapQuoteCard(card)
                return <div key={makeNumber()}>{currCard}</div>
            })}
            {displayExtraModal()}
        </Container>
    )
}

export default AqgSetup2

希望这是最终的解决方案,一切都会好起来的!