Создание компонентов на основе массива состояний и предоставление каждому компоненту атрибута setState для массива приводит к странному поведению. Может быть из-за параллельных изменений состояния? Попробуйте фрагмент ниже. Нажатие на квадрат должно удалить его. Вместо этого всегда будет удален последний созданный квадрат.
Кажется, проблема в l ie в useEffect()
в компоненте Square
. Хотя во фрагменте это действительно бесполезно, я использую что-то подобное, чтобы сделать элементы перетаскиваемыми. Может кто-нибудь объяснить это поведение и предложить решение? Я чувствую, что пропустил что-то важное о Реакте здесь.
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
, чтобы непреднамеренно не изменить предыдущее состояние.
Проблема остается, хотя ... всегда последний квадрат исчезает на экране. Использование эффекта при каждом повторном рендеринге показывает, что состояние обновляется правильно. Что мне здесь не хватает?