#javascript #reactjs #react-hooks #rendering #use-effect
Вопрос:
Предыстория проблемы
У меня проблема с моим крючком для реакции.
В принципе, я хочу повторно отобразить свои <li>
компоненты (названные elementsToDisplay
в приведенном ниже коде), когда пользователь изменяет порядок их отображения или когда пользователь вводит строку поиска в элемент ввода текста для их фильтрации.
//...import statements here...
function myHook(props) {
const [searchString, setSearchString] = useState('') // Initially empty searchstirng
const [order, setOrder] = useState('order1') // Ordering is initially order1
const [myObjects, setObjects] = useState(props.myObjects) // The objects needed to create the elements to display
const [elementsToDisplay, setElementsToDisplay] = useState([]) // The <li> elements to display (based on myObjects)
/*
IF THE SEARCHSTING OR THE ORDER GET CHANGED BY THE USER, CHANGE MY OBJECTS
*/
useEffect(() => {
var myObjectsCopy = [... props.myObjects]
myObjectsCopy.sort((a,b) => {
// Ordina in base a cosa l' utente ha selezionato dal sortByButton.
if (order == 'order1'){
// return some ordering
}
else if (order == 'order2'){
// return some ordering
}
else if (order == 'order3'){
// return some ordering
}
else{
// return some ordering
}
})
var newObjects = myObjectsCopy.filter(item => {
// filter based on searchsting
return item.productCode.toLowerCase().indexOf(searchString.toLowerCase()) >= 0
})
setObjects(newObjects)
console.log(myObjects[0]) // NOTE here myObjects get updated as expected everytime
}, [order, searchString])
/*
When myObjects change, so the <li> elements to display should (end they do!).
*/
useEffect(()=>{
var elements = get_elements_to_display()
setElementsToDisplay(elements)
console.log(elementsToDisplay[0]) // NOTE, elementsToDisplay change as expected!!!!!!
},[myObjects])
/*
Function that creates the <li> elements to display based on myObjects. NOTE works fine
*/
function get_elements_to_display(){
return myObjects.map((item, index) => {
var competitors = item.competitors
return(
<li key={index}>
<span className='produt-separator'/>
<ProductTable item={item} index={index} />
</li>
)
})
}
/*
Change the ordering to display the elements. NOTE Work as expected!!!
*/
function handleChangeOrder(e, value) {
e.preventDefault();
console.log(value) // NOTE the right ordering gets passed
setOrder(value)
console.log(order) // NOTE order gets updated as expected
}
/*
Render the component
*/
return (
<div>
<h1 className='page-title'>My Title</h1>
<input className="search-input" type='text'
onChange={e => setSearchString(e.target.value)}
placeholder='Cerca il toner o cartuccia per nome...'></input>
<span width="8px"/>
<SortByButton handleClick={handleChangeOrder}/>
<AddProductPopUp/>
<ul>
{elementsToDisplay}
</ul>
</div>
)
}
Проблема
Проблема в том, что все мои переменные состояния изменяются, как и ожидалось, но отображаемые <li>
компоненты остаются прежними. Это странно, так как они хранятся в состоянии elementsToDisplay
, и я вижу, что они обновляются всякий раз, когда я выбираю новый заказ или пытаюсь отфильтровать свои элементы, вводя строку поиска.
Можете ли вы увидеть, не делаю ли я что-то не так, из опубликованного мной примера кода?
Комментарии:
1. Вы пробовали изменить ключ списка
<li key={index}>
на какой-то другой уникальный идентификатор, кромеindex
? Кроме того, можем ли мы получить CodeSandbox для репликации проблемы, с которой вы столкнулись?2. @AreebKhan Ты мой спаситель. Смена
key=
реквизита на что-то уникальное сделала свое дело. Однако я не понимаю, в чем тут логика. Не могли бы вы опубликовать ответ с некоторым объяснением, чтобы я мог установить его в качестве принятого ответа?3. Да, конечно. Реакция использует ключи для определения того, какие элементы в списке изменились. Поскольку вы используете индекс в качестве ключа в нестатических экземплярах, а затем сортируете массив, из которого выполняете рендеринг, порядок индексов остается прежним. (1/2)
4. Другими словами, перед сортировкой динамического массива
[y,x,z]
и использованием их индекса в качестве ключа React в основном связываетсяy
с 0,x
с 1 иz
с 2. После сортировки массив становится[x,y,z]
и порядок элементов изменился, но элемент с индексом 0 по-прежнему первый! Теперь, поскольку React использует ключи для обнаружения изменений, и мы сохранили индексы в качестве ключей (порядок которых не меняется до и после сортировки), React не отображает изменения. Источник (2/2)
Ответ №1:
(Из комментариев)
Изменение ключа списка <li key={index}>
на какой-либо уникальный идентификатор, отличный index
от того, исправит это.
Реакция использует ключи для определения того, какие элементы в списке изменились. Поскольку вы используете индекс в качестве ключа в нестатических экземплярах, а затем сортируете массив, из которого выполняете рендеринг, порядок индексов остается прежним.
Ответ №2:
На этот вопрос был дан ответ в комментариях.