Apologies if you feel like this is a repeated question, but I couldn't find the solution for my problem in any of similar questions and couldn't understand why this problem was occurring.
I have a component called Selector.tsx
which basically has an input field and a bunch of buttons that when clicked are supposed to create a card with the data from that input field.
selector.tsx
:
const profileList: Profile[] = [
{
name: 'Website',
value: 'website',
},
{
name: 'Documentation',
value: 'documentation',
},
{
name: 'Telegram',
value: 'telegram',
},
{
name: 'Twitter',
value: 'twitter',
},
{
name: 'Github',
value: 'github',
},
{
name: 'Facebook',
value: 'facebook',
},
{
name: 'Blog',
value: 'blog',
},
{
name: 'Discord',
value: 'discord',
},
{
name: 'LinkedIn',
value: 'linkedin',
},
{
name: 'Slack',
value: 'slack',
},
];
export const Selector: FC<SelectorProps> = ({ wrapperClass }) => {
const [inputVal, setInputVal] = useState('https://google.com');
const [saved, setSaved] = useState<Saved[]>([]);
const handleAdd = (val: string) => {
if (!inputVal) return;
const _saved = saved;
_saved.push({ type: val, text: inputVal });
setSaved(_saved);
};
const handleClearSaved = () => {
setSaved([]);
};
const DisplayCard: FC<DisplayCardProps> = ({ text, type }) => (
<div className="w-full text-left text-text-gray bg-red-100 px-4 py-1 border rounded-lg">
<span className="text-gray-600 text-xs">{type}:</span>
<span className="text-base text-black text-sm ml-4">{text}</span>
</div>
);
return (
<div className="mt-4 py-4 flex flex-col lg:flex-row-reverse gap-4 items-center">
<div className="mt-8 space-y-2 overflow-y-auto border border-blue-500 p-4 rounded">
{saved.length ? (
saved.map(({ type, text }, i) => (
<DisplayCard key={i} text={text} type={type} />
))
) : (
<i>Nothing to show</i>
)}
</div>
<div className="border rounded p-4">
<div className="flex items-center gap-2">
<input
className="flex-grow pl-2 text-sm leading-6 border border-transparent bg-blue-100 rounded outline-none focus:border-prim-border"
value={inputVal}
onChange={(e) => setInputVal(e.target.value)}
/>
<div className="mt-2 flex flex-col space-y-2">
{profileList.map(({ name, value }, i) => (
<button
className="border border-red-400 text-sm bg-black bg-opacity-0 hover:bg-opacity-10 transform scale-100 active:scale-90 disabled:cursor-not-allowed"
onClick={() => handleAdd(value)}
disabled={!inputVal}
>
{name}
</button>
))}
</div>
</div>
<button
className="mt-2 border border-red-500 transform scale-100 active:scale-90 px-2"
onClick={handleClearSaved}
>
Clear Fields
</button>
</div>
</div>
);
};
Whenever we click any of the profile buttons (and the input field is not empty), the handleSave
button is called & saved
array state is supposed to get updated(object is pushed into the array) & based on that, DisplayCard
s are rendered.
The problem: The saved
state doesn't get updated after any of the profile buttons are clicked. When we make changes in the input field(which updates the inputVal
state), only then the saved
state gets updated
Also weirdly enough, the handleClearSaved
function works properly when the clear button is clicked. It is able to empty the saved
array. But for some reason, pushing into the saved
array doesn't seem to update the state.
Problem repoduced in Stackblitz: https://stackblitz.com/edit/well-well-well?file=components/Selector.tsx
I can't wrap my head around, why this behavior is occurring in react. I've never encountered such issues before. If any one can help or provide any hints on this, it would be really helpful.