Как избежать повторного рендеринга React Hooks - PullRequest
0 голосов
/ 18 июня 2020

Привет, я новый разработчик на ReactJs. У меня вопрос по поводу крючков. Я знаю, что есть так много ответов об этом квесте, но я не интегрировал эти решения в свой проект. У меня есть родительский и дочерний компоненты. Я передаю значение от ребенка к родителю. Когда я пытаюсь отправить данные с помощью функции обратного вызова, родительский элемент повторно выполняет рендеринг при получении элемента, поэтому я потерял свое значение selected в 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;

Ответы [ 3 ]

0 голосов
/ 19 июня 2020

Привет. Вместо того, чтобы поддерживать логическое значение в дочернем элементе, чтобы увидеть, выбран элемент или нет, вы можете передать это значение от родителя к потомку. Итак, родительский компонент:

   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;

Еще один совет: не рекомендуется отправлять данные из дочернего компонента в родительский.

0 голосов
/ 19 июня 2020

Единственная причина, по которой ваш дочерний элемент теряет свое состояние при повторном рендеринге родительского компонента, заключается в том, что вы назначаете новый ключ дочернему компоненту при сопоставлении.

Назначение ключа, который является уникальным, но также остается неизменным в течение -renders предотвратит возникновение этой проблемы.

Если ключ к компоненту изменяется, он не перерисовывается, а повторно монтируется, и, следовательно, значения состояния сбрасываются

Вы также можете использовать 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>
            }
          </>
        )
      })
    }
  )
0 голосов
/ 18 июня 2020

Вы можете просто передать значение selected от родительского компонента дочернему и инициировать выбранное состояние, используя эти реквизиты. . Вы можете передать null в качестве начального значения для selected через props. Итак, вы назовете дочерний компонент следующим образом:

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