嗨,我是 ReactJs 的新开发人员。我有一个关于钩子的问题。我知道关于这个任务有很多答案,但我没有将这些解决方案集成到我的项目中。我有父组件和子组件。我正在将价值从孩子传递给父母。当我尝试通过 react 回调函数发送数据时,父级在获取项目时正在重新渲染,因此我在 Child 上丢失了所选值。我该如何保护这些问题?你能给我什么建议吗?
父组件 :
import React,{useCallback,useState} from 'react'
const Dropable = ({item}) => {
const [list, setList] = useState(item)
const [selectedItems, setSelectedItems] = useState<Array<any>>([])
const handleSelectedItems = useCallback( (data: any) => {
if (data.type === "player") {
if (selectedItems.length === 0) {
const arr = selectedItems
arr.push(data)
setSelectedItems(arr)
}
}, [selectedItems],
)
return (
{list.map((data: any, index: any) => {
return (
<>
{
<div onClick={() => handleSelectedItems(index, data)}>
<Detailed
key={uuid()}
data={data}
dataIndex={index}
/>
</div>
}
</>
)
})}
)
}
export default Dropable;
子组件:
import React,{useState} from 'react'
const Detailed : React.FC<IProps> = (props) {
const [selected, setSelected] = useState(false)
const handleSelect = () => {
if (selected) {
setSelected(false)
}
else {
setSelected(true)
}
}
return (
<div onClick={handleSelect} className="detail" style={selected?{border: " 1px solid #5c6ef5"}: {}}>
</div>
)
}
export default Detailed;
嗨,与其在子项中维护布尔值以查看是否选择了该项,不如将该值从父项传递到子项。 所以父组件:
const Dropable = ({ item }) => {
const [list, setList] = useState(item)
const [selectedItems, setSelectedItems] = useState<Array<any>>([])
const handleSelectedItems = useCallback((data: any) => {
if (data.type === "player") {
if (selectedItems.length === 0) {
const arr = selectedItems
arr.push(data)
setSelectedItems(arr)
}
}, [selectedItems],
)
return (
{
list.map((data: any, index: any) => {
return (
<>
{
<div onClick={() => handleSelectedItems(index, data)}>
<Detailed
key={uuid()}
data={data}
dataIndex={index}
selected={selectedItems[0][ANY_KEY] === data[ANY_key]}
/>
</div>
}
</>
)
})
}
)
}
export default Dropable;
和您的子组件: 无需使用 useState 来设置值,因为我们在父组件中执行相同的工作。
import React,{useState} from 'react'
const Detailed : React.FC<IProps> = (props) {
return (
<div className="detail" style={props.selected?{border: " 1px solid
#5c6ef5"}: {}}>
</div>
)
}
export default Detailed;
还有一个提示:将数据从子组件发送到父组件不是一个好的做法。
您只需将selected
值从父组件传递到子组件,并使用该 props 启动所选状态。
const [selected, setSelected] = useState(props.selected)
然后,每次父级更新时,子项的选定状态都不会为 null。 您可以通过 props 传递 null 作为所选的初始值。因此,您将像这样调用子组件,
import React,{useCallback,useState} from 'react'
const Dropable = ({item}) => {
const [list, setList] = useState(item)
const [selectedItems, setSelectedItems] = useState<Array<any>>([])
const handleSelectedItems = useCallback( (data: any) => {
if (data.type === "player") {
if (selectedItems.length === 0) {
const arr = selectedItems
arr.push(data)
setSelectedItems(arr)
}
}, [selectedItems],
)
return (
{list.map((data: any, index: any) => {
const isSelected = selectedItems.findIndex(item => item.[some_unique_attribute] === data.[some_unique_attribute]) > -1;
return (
<>
{
<div onClick={() => handleSelectedItems(index, data)}>
<Detailed
key={uuid()}
data={data}
dataIndex={index}
selected={isSelected}
/>
</div>
}
</>
)
})}
)
}
当父组件重新呈现时,子组件丢失其状态的唯一原因是您在映射时为子组件分配了新键
分配一个唯一但在重新渲染中保持不变的键将防止此问题发生
如果组件的键发生更改,则不会重新渲染,而是重新挂载,因此状态值将重置
如果数据中没有唯一键,则可以使用a unique value as key from data
或替代使用index
。但是,您必须尝试在数据中至少有 1 个字段,可用于唯一标识它
return (
{
list.map((data: any, index: any) => {
return (
<>
{
<div onClick={() => handleSelectedItems(index, data)}>
<Detailed
key={data.id} // if no id field. You can assign index
data={data}
dataIndex={index}
selected={selectedItems[0][ANY_KEY] === data[ANY_key]}
/>
</div>
}
</>
)
})
}
)