Создание компонентов на основе массива состояний и присвоение каждому компоненту атрибута setState массива приводит к странному поведению. Может из-за параллельных изменений состояния? Попробуйте приведенный ниже фрагмент. Щелчок по квадрату должен удалить его. Вместо этого всегда будет удаляться последний созданный квадрат.
Проблема, кажется, заключается в useEffect()
в компоненте Square
. Хотя во фрагменте это действительно бесполезно, я использую что-то подобное, чтобы сделать элементы перетаскиваемыми. Может ли кто-нибудь объяснить это поведение и предложить решение? Я чувствую, что пропустил что-то важное о React здесь.
function Square(props){
const [pos, setPos] = React.useState([props.top, props.left])
React.useEffect(() => {
props.setSquares(prevState => prevState.map((square, index) => index === props.index ? {...square, top: pos + 20} : square
))
}, [pos])
function deleteMe(){
props.setSquares(prevState => prevState.filter((square, index) => index !== props.index))
}
return <div onClick={deleteMe}
style={{top: pos[0]+'px', left: pos[1]+'px'}}
className='square'>
</div>
}
function App(){
const [squares, setSquares] = React.useState([
{top: 20, left: 0},{top: 20, left: 100},
{top: 20, left: 200},{top: 20, left: 300}])
React.useEffect(() => console.log('rerender', ...squares.map(s => s.left)))
return <div>{squares.map((square, index) => <Square
setSquares={setSquares} index={index}
top={square.top} left={square.left}/>)}</div>
}
ReactDOM.render(<App/>, document.getElementById('root'))
.square{
position: absolute;
width: 80px;
height: 80px;
background: orange;
}
<div id='root'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
Редактировать: Как предложил Ник в комментариях, я изменил методы setSquare
, чтобы использовать prevState.map
и filter
, чтобы не изменять предыдущее состояние непреднамеренно.
Однако проблема остается ... всегда последний квадрат исчезает на экране. Использование эффекта при каждом повторном рендеринге показывает, что состояние обновляется правильно. Что мне здесь не хватает?