React 状态不会随 useState 立即更新
React state doesn't update immediately with useState
如果您觉得这是一个重复的问题,我深表歉意,但我在任何类似问题中都找不到解决我的问题的方法,也无法理解为什么会出现此问题。
我有一个名为 Selector.tsx
的组件,它基本上有一个输入字段和一堆按钮,单击这些按钮应该会使用该输入字段中的数据创建一张卡片。
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>
);
};
每当我们单击任何配置文件按钮(并且输入字段不为空)时,handleSave
按钮将被调用 & saved
数组状态应该得到更新(对象被推入数组)&基于此,DisplayCard
被渲染。
问题: 单击任何配置文件按钮后,saved
状态不会更新。当我们在输入字段中进行更改(更新 inputVal
状态)时,只有 saved
状态才会更新
同样奇怪的是,单击清除按钮时 handleClearSaved
功能正常工作。 可以清空saved
数组。但是由于某种原因,推入saved
数组似乎并没有更新状态.
Stackblitz 中重现的问题:https://stackblitz.com/edit/well-well-well?file=components/Selector.tsx
我无法理解为什么这种行为会在反应中发生。我以前从未遇到过此类问题。
如果有人可以提供帮助或提供任何提示,那将非常有帮助。
谢谢。
使用这个直接改变状态:
const handleAdd = (val: string) => {
if (!inputVal) return;
setSaved(prevState => [...prevState, {type: val, text: inputVal}]);
};
此外,您应该在按钮映射中添加一个 key
,它会给您一个控制台错误。
原因是您正在使用引用进行变量(对象)复制,当引用未更改时您的状态未更新
代替
const handleAdd = (val: string) => {
if (!inputVal) return;
const _saved = saved;
_saved.push({ type: val, text: inputVal });
setSaved(_saved);
};
试试这个代码
const handleAdd = (val: string) => {
if (!inputVal) return;
setSaved((pre) => ([...pre, { type: val, text: inputVal });
};
对象和数组通过引用工作,这意味着你不能像这样复制它们
const a = [1,2,3]
const b = a
要复制数组,您应该使用 ES6 Spread 语法来创建这样的新实例
const a = [1,2,3]
cosnt b = [...a]
反应状态检查前一个值和下一个值然后进行更新
当参考没有改变时,不会发生渲染。要更新对象状态或数组状态,您应该创建新实例,并且可以使用 ES6 Spread 语法
如果您觉得这是一个重复的问题,我深表歉意,但我在任何类似问题中都找不到解决我的问题的方法,也无法理解为什么会出现此问题。
我有一个名为 Selector.tsx
的组件,它基本上有一个输入字段和一堆按钮,单击这些按钮应该会使用该输入字段中的数据创建一张卡片。
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>
);
};
每当我们单击任何配置文件按钮(并且输入字段不为空)时,handleSave
按钮将被调用 & saved
数组状态应该得到更新(对象被推入数组)&基于此,DisplayCard
被渲染。
问题: 单击任何配置文件按钮后,saved
状态不会更新。当我们在输入字段中进行更改(更新 inputVal
状态)时,只有 saved
状态才会更新
同样奇怪的是,单击清除按钮时 handleClearSaved
功能正常工作。 可以清空saved
数组。但是由于某种原因,推入saved
数组似乎并没有更新状态.
Stackblitz 中重现的问题:https://stackblitz.com/edit/well-well-well?file=components/Selector.tsx
我无法理解为什么这种行为会在反应中发生。我以前从未遇到过此类问题。 如果有人可以提供帮助或提供任何提示,那将非常有帮助。
谢谢。
使用这个直接改变状态:
const handleAdd = (val: string) => {
if (!inputVal) return;
setSaved(prevState => [...prevState, {type: val, text: inputVal}]);
};
此外,您应该在按钮映射中添加一个 key
,它会给您一个控制台错误。
原因是您正在使用引用进行变量(对象)复制,当引用未更改时您的状态未更新
代替
const handleAdd = (val: string) => {
if (!inputVal) return;
const _saved = saved;
_saved.push({ type: val, text: inputVal });
setSaved(_saved);
};
试试这个代码
const handleAdd = (val: string) => {
if (!inputVal) return;
setSaved((pre) => ([...pre, { type: val, text: inputVal });
};
对象和数组通过引用工作,这意味着你不能像这样复制它们
const a = [1,2,3]
const b = a
要复制数组,您应该使用 ES6 Spread 语法来创建这样的新实例
const a = [1,2,3]
cosnt b = [...a]
反应状态检查前一个值和下一个值然后进行更新 当参考没有改变时,不会发生渲染。要更新对象状态或数组状态,您应该创建新实例,并且可以使用 ES6 Spread 语法