Я дам вам некоторые замечания, касающиеся подсчета времени и уменьшения их значений при нажатии. Я объясняю основные проблемы в вашем коде и предоставляю иной подход к реализации, который позволяет вам продолжить работу с бизнес-логикой c.
1. правильный доступ к counts
forEach
l oop использует значения массива в качестве ключей для объекта counts
. Кажется, что вы скорее хотите использовать значение x.time
, потому что именно так вы позже получите к нему доступ (payload: counts[
$ {item.time} ]
). x
сам по себе является объектом.
2. правильное использование useReducer
useReducer
дает вам объект состояния в первом элементе возвращаемого массива. Вы немедленно разлагаете его, используя { counter }
. Значение этой переменной счетчика является начальным значением (''
). Ваш редуктор устанавливает значения в объекте состояния с ключами в виде counter${action.id}
, поэтому разложенная переменная counter
не изменится.
Я думаю, вы хотите что-то вроде этого:
const [counters, dispatchReducer] = useReducer(reducer, {}); // not decomposed, the counters variable holds the full state of all counters you add using your `SET_COUNTER` action.
Позже, когда вы пытаетесь визуализировать свои счетчики, вы в настоящее время делаете { counter }
, который всегда пуст (''
), поскольку это все еще относится к вашему первоначальному начальному состоянию. Теперь, когда counters
удерживает полное состояние, вы можете получить доступ к счетчику вашего объекта counters
для текущего элемента, используя его идентификатор:
{if (index > 0 &&
item.time === availableTimes[index - 1].time &&
item.time !== availableTimes[index - 2].time) {
return (
<span> {counters[`counter${item.id}`]} </span>
)
}
3. общая структура кода
Есть больше проблем, и код довольно сумасшедший и его очень трудно понять (например, из-за смешанных понятий в путанице). Даже если вы исправите упомянутые наблюдения, я сомневаюсь, что это приведет к тому, что вы делаете то, что хотите, или что вы когда-либо сможете поддерживать. Поэтому я придумал другую структуру кода, которая могла бы дать вам новое представление о том, как ее реализовать.
Вам не нужно useReducer
, потому что ваше состояние довольно плоское. Редукторы лучше подходят для более сложного состояния , но, в конце концов, это все еще локальное состояние компонента.
Я не знаю, чего именно вы хотите достичь при нажатии на элементы, поэтому я просто уменьшите счет, потому что я думаю, что это то, о чем этот вопрос.
Вот коды и поле следующего кода в действии: https://codesandbox.io/s/relaxed-roentgen-xeqfi?file= / src / App. js
import React, { useCallback, useEffect, useState } from "react";
const availableTimes = [
{ time: "07:30" },
{ time: "08:00" },
{ time: "08:00" },
{ time: "08:00" },
{ time: "09:30" },
{ time: "10:00" }
];
const CounterApp = () => {
const [counts, setCounts] = useState({});
useEffect(() => {
const counts = {};
availableTimes.forEach(x => {
counts[x.time] = (counts[x.time] || 0) + 1;
});
setCounts(counts);
}, []);
const onClick = useCallback(time => {
// Your logic on what to do on click goes here
// Fore example, I only reduce the count of the given time.
setCounts(prev => ({
...prev,
[time]: prev[time] - 1,
}));
}, []);
return (
<div>
<h2>Counts:</h2>
<ul>
{Object.keys(counts).map(time => (
<li key={time} onClick={() => onClick(time)}>
{time} ({counts[time]})
</li>
))}
</ul>
</div>
);
};
export default CounterApp;