ReactJS:Child 组件 re-rendering 来自 parent 的 OnChange 事件
ReactJS: Child component re-rendering on OnChange event from parent
我有一个包含两个 children 的 parent 组件:显示信息的 Child1 和通过输入更改信息的 Child2。我的目标是保持 Child1 的信息来自 re-rendering,直到保存触发器从 Child2 传递到 parent,这意味着数据已保存。为此,我在 Child1 中使用 memo 来记忆数据并将其保存在 re-rendering 中,但它不会起作用,因为每次触发 onChange 事件时 child 仍然是 re-rendered。如何让 Child1 在保存之前保持数据不变?这是我目前所拥有的:
孩子 1:
import React,{memo} from 'react'
const UserDetails = ({values,onOpen})=>{
console.log("child1 rendering")
return(
<Center>
<Box d="flex" justifyContent='space-between' w="xs">
<Heading name="username">{values.username}</Heading>
<IconButton size="md" icon={<FiPenTool />} onClick={onOpen} />
</Box>
</Center>
<Stack mt={10} direction={['column', 'column']}>
<Heading fontSize="20px">Location:{values.location}</Heading>
<Box mt={5} px={20}>
<Heading fontSize="20px">Description</Heading>
<Text fontSize="md">{values.description}</Text>
</Box>
</Stack>
)
}
export default memo(UserDetails)
孩子 2:
function PopUpDetails({ values, handleDetails })
{
console.log("child2 render")
return (
<Box>
<Input name="username" w="md" mt={5} mr={5} fontWeight="bold" textAlign="center"
value={values.username} onChange={handleDetails} />
<Input name="location" mt={5} fontWeight="bold" onChange={handleDetails}
textAlign="center"
w="md" mr={5}
onFocus={() => onOpen()} value={values.location} />
<Input name="description" w="md" h="20vh" mt={5} mr={5} textAlign="center"
fontWeight="bold" value={values.description} onChange={handleDetails} />
</Box>
)
}
export default PopUpDetails
Parent:
const userValues= {
username: '',
location:'',
description:''
}
function User() {
const { Moralis, user, setUserData, isUserUpdating } = useMoralis()
const currentUserId = user.id
const { isOpen, onOpen, onClose } = useDisclosure()
const params = { "userId": currentUserId }
const [details, setDetails] = useState(()=>()=>userHook())
const userHook = useCallback(()=>{ //callback function to retrieve initial values each time
user closes child2 in case data was not saved
setDetails({...details,
username:Moralis.User.current().attributes.username,
description: Moralis.User.current().attributes.description,
location: Moralis.User.current().attributes.location,
})
},[])
useEffect(()=>{
userHook()
},[])
const saveDetails = () =>{
setUserData({
location: details.location,
username: details.username,
description: details.description,
})
}
const handleInputChange = (e) => {
const { name, value } = e.target
setDetails({
...details,
[name]: value
})
}
return(
<Container>
<UserDetails values={details}/>
<Modal isOpen={isOpen} size="3xl" closeOnOverlayClick isCentered onClose={() => { onClose();userHook()}}>
<ModalOverlay />
<ModalContent >
<ModalHeader>Edit details</ModalHeader>
<ModalCloseButton />
<ModalBody>
<PopUpDetails values={details} handleDetails={(e) => handleInputChange(e)}/>
</ModalBody>
<ModalFooter>
<Button onClick={() => saveDetails()} variant='ghost'>Save</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Container>
)
export default User
谁能帮助我理解为什么 Child1 re-renders 每次即使我使用备忘录,我如何缓存数据以便在触发 handleChange 时它不会反映在 Child1 上?任何帮助将不胜感激!
<UserDetails values={details}/>
您的用户详细信息正在接收“值”prop 中的状态,这是您在模式中更改的状态,那么您为什么不希望重新呈现?
尝试将您的初始值放在一边,然后将其设置为默认状态并将其传递给您的组件以保持不变。
function User() {
const { Moralis, user, setUserData, isUserUpdating } = useMoralis()
const { isOpen, onOpen, onClose } = useDisclosure()
const params = { "userId": user.id }
const initValues = useMemo(() => {
const {
username,
description,
location
} = Moralis.User.current().attributes;
return { username, description, location };
}, []);
const [details, setDetails] = useState(initValues)
...
<UserDetails value={initValues} />
...
我有一个包含两个 children 的 parent 组件:显示信息的 Child1 和通过输入更改信息的 Child2。我的目标是保持 Child1 的信息来自 re-rendering,直到保存触发器从 Child2 传递到 parent,这意味着数据已保存。为此,我在 Child1 中使用 memo 来记忆数据并将其保存在 re-rendering 中,但它不会起作用,因为每次触发 onChange 事件时 child 仍然是 re-rendered。如何让 Child1 在保存之前保持数据不变?这是我目前所拥有的:
孩子 1:
import React,{memo} from 'react'
const UserDetails = ({values,onOpen})=>{
console.log("child1 rendering")
return(
<Center>
<Box d="flex" justifyContent='space-between' w="xs">
<Heading name="username">{values.username}</Heading>
<IconButton size="md" icon={<FiPenTool />} onClick={onOpen} />
</Box>
</Center>
<Stack mt={10} direction={['column', 'column']}>
<Heading fontSize="20px">Location:{values.location}</Heading>
<Box mt={5} px={20}>
<Heading fontSize="20px">Description</Heading>
<Text fontSize="md">{values.description}</Text>
</Box>
</Stack>
)
}
export default memo(UserDetails)
孩子 2:
function PopUpDetails({ values, handleDetails })
{
console.log("child2 render")
return (
<Box>
<Input name="username" w="md" mt={5} mr={5} fontWeight="bold" textAlign="center"
value={values.username} onChange={handleDetails} />
<Input name="location" mt={5} fontWeight="bold" onChange={handleDetails}
textAlign="center"
w="md" mr={5}
onFocus={() => onOpen()} value={values.location} />
<Input name="description" w="md" h="20vh" mt={5} mr={5} textAlign="center"
fontWeight="bold" value={values.description} onChange={handleDetails} />
</Box>
)
}
export default PopUpDetails
Parent:
const userValues= {
username: '',
location:'',
description:''
}
function User() {
const { Moralis, user, setUserData, isUserUpdating } = useMoralis()
const currentUserId = user.id
const { isOpen, onOpen, onClose } = useDisclosure()
const params = { "userId": currentUserId }
const [details, setDetails] = useState(()=>()=>userHook())
const userHook = useCallback(()=>{ //callback function to retrieve initial values each time
user closes child2 in case data was not saved
setDetails({...details,
username:Moralis.User.current().attributes.username,
description: Moralis.User.current().attributes.description,
location: Moralis.User.current().attributes.location,
})
},[])
useEffect(()=>{
userHook()
},[])
const saveDetails = () =>{
setUserData({
location: details.location,
username: details.username,
description: details.description,
})
}
const handleInputChange = (e) => {
const { name, value } = e.target
setDetails({
...details,
[name]: value
})
}
return(
<Container>
<UserDetails values={details}/>
<Modal isOpen={isOpen} size="3xl" closeOnOverlayClick isCentered onClose={() => { onClose();userHook()}}>
<ModalOverlay />
<ModalContent >
<ModalHeader>Edit details</ModalHeader>
<ModalCloseButton />
<ModalBody>
<PopUpDetails values={details} handleDetails={(e) => handleInputChange(e)}/>
</ModalBody>
<ModalFooter>
<Button onClick={() => saveDetails()} variant='ghost'>Save</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Container>
)
export default User
谁能帮助我理解为什么 Child1 re-renders 每次即使我使用备忘录,我如何缓存数据以便在触发 handleChange 时它不会反映在 Child1 上?任何帮助将不胜感激!
<UserDetails values={details}/>
您的用户详细信息正在接收“值”prop 中的状态,这是您在模式中更改的状态,那么您为什么不希望重新呈现?
尝试将您的初始值放在一边,然后将其设置为默认状态并将其传递给您的组件以保持不变。
function User() {
const { Moralis, user, setUserData, isUserUpdating } = useMoralis()
const { isOpen, onOpen, onClose } = useDisclosure()
const params = { "userId": user.id }
const initValues = useMemo(() => {
const {
username,
description,
location
} = Moralis.User.current().attributes;
return { username, description, location };
}, []);
const [details, setDetails] = useState(initValues)
...
<UserDetails value={initValues} />
...