简体   繁体   English

如何避免 React Hooks 的重新渲染

[英]How to avoid re-render of React Hooks

Hi I am new developer at ReactJs.嗨,我是 ReactJs 的新开发人员。 I have a question about Hooks.我有一个关于 Hooks 的问题。 I know there are so many answers about this quest but I did not integrate that solutions to my project.我知道关于这个任务有很多答案,但我没有将这些解决方案集成到我的项目中。 I have parent and child component.我有父子组件。 I am passing value from child to parent.我正在将价值从孩子传递给父母。 When I try to send a data via react callback function, parent is re-rendering while taking item and so I lost my selected value on Child.当我尝试通过反应回调 function 发送数据时,父级在获取项目时重新渲染,因此我在子级上丢失了我选择的值。 How can I protect that problems?我该如何保护这些问题? Could you any advice to me?你能给我什么建议吗?

Parent Component:父组件:

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;

Child Component:子组件:

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;

You can simply pass the selected value from parent to child component and initiate the selected state using that props.您可以简单地将selected的值从父组件传递给子组件,并使用该道具启动选定的 state。

const [selected, setSelected] = useState(props.selected)

Then every time the parent updates, the child's selected state will not be null.那么每次父更新,子选择的state就不会是null了。 You can pass null as initial value for selected via props.您可以通过 null 作为通过道具选择的初始值。 So, you will call the child component like this,所以,你会这样调用子组件,

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>
                }
            </>
        )
    })}
  )
}

Hi Instead of maintaining the boolean value in the child to see if the item is selected or not you can pass that value from parent to child.嗨,您可以将该值从父级传递给子级,而不是在子级中维护 boolean 值以查看该项目是否被选中。 So the parent component:所以父组件:

   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;

And your child component: There is no need to use useState to set the value coz we are doing the same work in the parent component.还有你的子组件:不需要使用 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;

One more tip: It is not a good practice to send data from child component to parent.另一个提示:将数据从子组件发送到父组件不是一个好习惯。

The only reason that your child loses its state when the parent re-renders is because you are assigning a new key to the Child component while mapping当父级重新渲染时,您的子级丢失其 state 的唯一原因是因为您在映射时为子组件分配了一个新键

Assigning a key that is unique but also remains same across re-renders will prevent this problem from happening分配一个唯一但在重新渲染时保持相同的键将防止此问题发生

If the key to a component changes, its not re-rendered but re-mounted and hence state values are reset如果组件的键发生变化,它不会重新渲染而是重新安装,因此 state 值被重置

Either you can use a unique value as key from data or alternative use index if there is no unique key in data.如果数据中没有唯一键,您可以使用a unique value as key from data或替代使用index However you must try to have atleast 1 field in data which can be used to uniquely identify it但是,您必须尝试在数据中至少包含 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>
            }
          </>
        )
      })
    }
  )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM