Consistent useEffect timing: React now always synchronously flushes effect functions if the update was triggered during a discrete user input event such as a click or a keydown event.
document
, дальше событие клика по кнопке продолжило всплывать и попало в только что установленный обработчик.При добавлении задержки, данная проблема уходит
document.addEventListener('click', handleOutsideClick, true);
return () => document.removeEventListener('click', handleOutsideClick, true);
const components = [
[ 'Day', Components1 ],
[ 'Week', Components2 ],
[ 'Month', Components3 ],
[ 'Year', Components4 ],
];
const [ active, setActive ] = useState(-1);
const Component = components[active]?.[1];
const onClick = e => setActive(+e.target.dataset.index);
{components.map((n, i) => <button data-index={i} onClick={onClick}>{n[0]}</button>)}
{Component && <Component />}
ключ уже есть
undefined
- это не ключ. Откуда берётся undefined
? Из-за отсутствия свойства id
, значение которого должно быть ключом. Как оно пропадает? Да вот так:return { ...emojis, count: emoji.count + 1 }
...emojis
должно быть ...emoji
.Winner
не количество голосов, а элемент smiles
целиком. Да, Math.max
получить его не поможет, придётся самостоятельно перебирать массив в поисках максимума.const Winner = ({ winner }) => winner
? <div>{winner.text}: {winner.value}</div>
: null;
class App extends React.Component {
state = {
winner: null,
smiles: [ 128540, 128520, 128640, 128526, 128566 ].map((n, i) => ({
id: i + 1,
text: String.fromCodePoint(n),
value: 0,
})),
}
vote(index) {
this.setState(({ smiles }) => ({
winner: null,
smiles: smiles.map((n, i) => i === index
? { ...n, value: n.value + 1 }
: n
),
}));
}
showWinner = () => {
this.setState(({ smiles }) => ({
winner: smiles.reduce((max, n) => max.value > n.value ? max : n),
}));
}
render() {
const { smiles, winner } = this.state;
return (
<div>
<ul>
{smiles.map((n, i) => (
<li key={n.id}>
<button onClick={() => this.vote(i)}>{n.text}: {n.value}</button>
</li>
))}
</ul>
<button onClick={this.showWinner}>show winner</button>
<Winner winner={winner} />
</div>
);
}
}
checkWinner(id) { console.log({[id]: Math.max(...Object.values(this.state))})
onClick={checkWinner}
[object Object]
- дефолтное строковое представление объекта. Всё. useEffect(() => {
const timeoutID = setTimeout(nextSlide, 3000);
return () => clearTimeout(timeoutID);
}, [ currentIndex ]);
setProducts(products => products.map(n => {
const card = n.cards.find(m => m.id === id);
return card
? {
...n,
cards: n.cards.map(m => m === card
? { ...m, quantity: newQuantity }
: m
),
}
: n
}));
function App() {
const [ count, setCount ] = useState(() => +localStorage.getItem('count') || 0);
useEffect(() => {
localStorage.setItem('count', count);
}, [ count ]);
const onClick = e => setCount(count => count + +e.target.dataset.change);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={onClick} data-change="+1">+</button>
<button onClick={onClick} data-change="-1">-</button>
</div>
);
}
const sortedData = useMemo(() => {
return data
.pages
.flatMap(n => n.data)
.sort((a, b) => b.liked.length - a.liked.length);
}, [ data ]);
<div className="App">
{sortedData.map((item) => (
<div>
...
const [posts, setPosts] = useState([]);
setPosts(fetchReq);
const fetchReq = fetch(`${fetchURL}/posts`).then(res => res.json());
fetch(`${fetchURL}/posts`)
.then(r => r.json())
.then(setPosts);
const amounts = [ 5, 10, 15 ];
const [ amount, setAmount ] = useState(null);
const [ isCustomAmount, setIsCustomAmount ] = useState(false);
{amounts.map(n => (
<label>
<input
type="radio"
disabled={isCustomAmount}
checked={amount === n && !isCustomAmount}
onChange={() => setAmount(n)}
/>
${n}
</label>
))}
<label>
<input
type="checkbox"
checked={isCustomAmount}
onChange={e => (setAmount(null), setIsCustomAmount(e.target.checked))}
/>
Другая сумма
</label>
{isCustomAmount && <input value={amount} onChange={e => setAmount(+e.target.value)} />}
<input type="hidden" name="amountusd" value={amount} />
const editTodo = (id, title) => {
setTodos(todos.map(n => n.id === id
? { ...n, title }
: n
));
};
function TodoItem({ complete, title, id, removeTodo, toggleTodo, editTodo }) {
const [ isEdit, setIsEdit ] = useState(false);
const [ editValue, setEditValue ] = useState('');
return (
<div className="todo-item">
<input type="checkbox" checked={complete} onChange={() => toggleTodo(id)} />
{isEdit
? <>
<input value={editValue} onChange={e => setEditValue(e.target.value)} />
<button onClick={() => (setIsEdit(false), editTodo(id, editValue))}>Save</button>
<button onClick={() => setIsEdit(false)}>Cancel</button>
</>
: <span onDoubleClick={() => (setIsEdit(true), setEditValue(title))}>{title}</span>
}
<button onClick={() => removeTodo(id)}>X</button>
</div>
);
}
const dashoffset = circleRef.current - ...
NaN
.const getSctollTop = () => { return window.pageYOffset || document.documentElement.scrollTo; }
scrollTo
? Это же метод, а вы вроде бы число хотите получить. Может, scrollTop
?React.useEffect(() => { ... window.addEventListener("scroll", () => { ... }); }, []);
const [ showAll, setShowAll ] = useState(false);
const defaultShow = 2;
const showAllByDefault = ingredients.length <= defaultShow;
const ingredientsToShow = (showAll || showAllByDefault)
? ingredients
: ingredients.slice(0, defaultShow);
{showAllByDefault
? null
: <button onClick={() => setShowAll(val => !val)}>{showAll ? 'hide' : 'show'}</button>
}
<ul>
{ingredientsToShow.map(n => <li>{n}</li>)}
</ul>
function Typewriter({ text }) {
const [ length, setLength ] = useState(0);
useEffect(() => {
setLength(0);
const interval = setInterval(setLength, 100, length => {
if (++length >= text.length) {
clearInterval(interval);
}
return length;
});
return () => clearInterval(interval);
}, [ text ]);
return <div>{text.slice(0, length)}</div>;
}
nextEl: prevRef.current
const [ swiper, setSwiper ] = useState();
<Swiper
onSwiper={setSwiper}
...
- ref={prevRef}
+ onClick={() => swiper.slidePrev()}
срабатывает дважды, а в последующие разы увеличивается в разы
useEffect(() => { window.addEventListener('keydown', onKeyPress); }, [focus])
useEffect(() => {
const onKeyDown = ({ keyCode }) => {
if (keyCode === 39) {
setFocus(focus => focus + 1);
}
};
window.addEventListener('keydown', onKeyDown);
return () => window.removeEventListener('keydown', onKeyDown);
}, []);
state = {
phones: [
{ id: 1, title: '', number: '' },
],
}
onChange = ({ target: { value, name, dataset: { index } } }) => {
this.setState(({ phones }) => ({
phones: phones.map((n, i) => +index === i
? { ...n, [name]: value }
: n
),
}));
}
addPhone = () => {
this.setState(({ phones }) => ({
phones: [
...phones,
{
id: 1 + Math.max(...phones.map(n => n.id)),
title: '',
number: '',
},
],
}));
}
delPhone = ({ target: { dataset: { index } } }) => {
this.setState(({ phones }) => ({
phones: phones.filter((n, i) => i !== +index),
}));
}
render() {
return (
<div>
{this.state.phones.map((n, i) => (
<div key={n.id}>
<input name="title" data-index={i} value={n.title} onChange={this.onChange} />
<input name="number" data-index={i} value={n.number} onChange={this.onChange} />
{i ? <button data-index={i} onClick={this.delPhone}>x</button> : null}
</div>
))}
<button onClick={this.addPhone}>Add</button>
</div>
);
}