当前位置: 首页 > 知识库问答 >
问题:

react.js - react函数里的state不更新,咋办?

祁承嗣
2024-04-17

场景

在这里插入图片描述
有一个聊天输入框组件,输入框上面有表情包组件。
通过redux创建了store,存储一个message的状态,用于表情包和输入框共享状态。
输入框通过设置value和onClick做了一个简单双向绑定,其中value的值为store里的message。

import { update } from "@/features/messageSlice";import { useStoreSelector, useStoreDispatch } from "@/hooks/store";const ChatInput: React.FC = () => {  const message = useStoreSelector((state) => state.message.value);  const dispatch = useStoreDispatch();  return (    <textarea      value={message}      onChange={(e) => {        const val = (e.target as HTMLTextAreaElement).value;        dispatch(update(val));      }}      className="chatInput"      style={{        width: "100%",        resize: "none",        outline: "none",        border: "none",      }}    ></textarea>  );};export default ChatInput;

表情包组件做了一个方法,选择表情包时通过回调传回值与message值做拼接,结果message值为上一次的值

import { useStoreSelector, useStoreDispatch } from "@/hooks/store";import { update } from "@/features/messageSlice";import DIcon from "@/components/DIcon";import { chatTools } from "../../config";import { Tooltip } from "antd";const ChatTools: React.FC = () => {  const message = useStoreSelector((state) => state.message.value);  const dispatch = useStoreDispatch();  const onSelectContent = (ct: any) => {    dispatch(update(message + ct.emoji));  };  return (    <div className="chatTools">      {chatTools.map(({ icon, tooltip, extra }) => {        const Comp: any = extra;        return (          <Tooltip key={icon} placement="top" title={tooltip}>            <Tooltip              placement="top"              overlayStyle={{ maxWidth: "100%" }}              overlayInnerStyle={{ color: "#000000" }}              color="#ffffff"              title={<Comp onSelectContent={onSelectContent}></Comp>}              trigger="click"            >              <span style={{ margin: "0 12px 0 0" }}>                <DIcon type={icon} style={{ fontSize: "24px" }}></DIcon>              </span>            </Tooltip>          </Tooltip>        );      })}    </div>  );};export default ChatTools;

结果:当我输入一段文字后,添加一个表情包,再输入一段文字,再添加一个表情包时。。就会覆盖掉前一段文字。

个人尝试:
1.设置一个state存储选择的表情包,然后通过useEffect监听state的变化更新message。结果出现新bug,那就是不能重复选择表情包,因为state不改变导致useEffect不执行。
2.仔细分析了一下原因,是Tooltip组件未更新,导致message是属于第一次闭包的。在内嵌的Tooltips添加了一个key,值为message。结果成功,但是有个警告
在这里插入图片描述

共有1个答案

法玮
2024-04-17

问题出在于你的 Redux 状态更新是异步的,但是你在 onSelectContent 方法中试图立即使用新的状态值。当你在 Redux 中派发一个 action 时,状态并不会立即更新,而是在下一个渲染周期中更新。因此,你在 onSelectContent 方法中使用的 message 值仍然是旧的,而不是你期望的新值。

要解决这个问题,你可以使用 Redux 的 useSelector 钩子的第二个参数,这是一个依赖数组。当这个数组中的任何值发生变化时,useSelector 会重新运行,并返回新的值。在你的情况下,你可以将 message 添加到这个数组中,这样每当 message 更新时,useSelector 都会返回新的值。

另外,关于你提到的警告,这个警告是由于你在 Tooltip 组件中使用了不稳定的 key。在你的情况下,message 是一个可能会频繁变化的值,所以用它作为 key 是不稳定的,这可能会导致性能问题和渲染错误。

下面是修改后的代码:

import { useStoreSelector, useStoreDispatch } from "@/hooks/store";import { update } from "@/features/messageSlice";import DIcon from "@/components/DIcon";import { chatTools } from "../../config";import { Tooltip } from "antd";const ChatTools: React.FC = () => {  const dispatch = useStoreDispatch();  const [message, setMessage] = React.useState("");  React.useEffect(() => {    setMessage(useStoreSelector((state) => state.message.value));  }, []); // 监听 Redux store 中的 message 变化  const onSelectContent = (ct: any) => {    dispatch(update(message + ct.emoji));  };  return (    <div className="chatTools">      {chatTools.map(({ icon, tooltip, extra }) => {        const Comp: any = extra;        return (          <Tooltip key={icon} placement="top" title={tooltip}>            <Tooltip              placement="top"              overlayStyle={{ maxWidth: "100%" }}              overlayInnerStyle={{ color: "#000000" }}              color="#ffffff"              title={<Comp onSelectContent={onSelectContent}></Comp>}              trigger="click"            >              <span style={{ margin: "0 12px 0 0" }}>                <DIcon type={icon} style={{ fontSize: "24px" }}></DIcon>              </span>            </Tooltip>          </Tooltip>        );      })}    </div>  );};export default ChatTools;

在这个修改后的版本中,我创建了一个新的 state message 来存储从 Redux store 中获取的消息。然后,我使用 useEffect 来监听 Redux store 中的 message 变化,并在变化时更新这个 state。这样,你就可以在 onSelectContent 方法中使用这个稳定的 message 值了。

同时,我也移除了 Tooltip 组件中的 key 属性,因为使用不稳定的值作为 key 可能会导致性能问题和渲染错误。由于你的 Tooltip 组件的 key 是基于图标的,这应该是稳定的,所以移除 key 属性应该是安全的。

希望这个解答能帮到你!如果你还有其他问题,欢迎继续提问。

 类似资料:
  • 我在react中观看crud全堆栈教程时,浏览器上出现了这个错误

  • 用的是 React 和 Antd v5 为什么在改了 state 之后元素还是没变化呢 问过 GPT 但是没有结果

  • react 在 A 函数设置了state 然后调用 B函数,B函数中使用了state,但直接获取state不是最新值。 使用Effect和通过函数参数传递来解决,感觉都不优雅,大佬们有没有比较好的经验?

  • 场景 我有一个父组件,里面包含一个子组件,子组件传入了一个对象,假设对象是字面量。当我的父组件更新时,子组件也会更新。导致不必要的渲染。 尝试 1.通过使用React.memo包裹子组件,作用是父组件更新,子组件只有当props变化才变化。结果发现还是不对。。。。分析了一下原因是,当父组件更新时候,传入到子组件的的引用发生了变化,虽然值是相同的。。。咋搞

  • 我正在尝试使用DidMount中的localStorage值更新状态,但它没有更新: 在第一个console.log中,我的值为1,在第二个中,它保持为空,不更新状态。

  • 问题内容: 我知道都存在一些类似的问题,但是我很难理解今天对这个问题的正确想法并将其推断出我的处境。 我有一个简单的应用程序,ScoreBox有一个ScoreList,其中包含很多分数。我想让Score onClick调用ScoreList handleScoreRemove。我正在显示完整的js文件,但最重要的行是第5行和第77行。 问题答案: 你需要通过 并在组件中这样称呼它