将状态从 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
希望这是最终的解决方案,一切都会好起来的!
我正在尝试从反应组件中的函数访问我的状态,称为 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
希望这是最终的解决方案,一切都会好起来的!