使用 setState 时反应状态不变

React state not changing, when using setState

我试图让一个开关在用户与之交互时变为 enabled/disabled。这是通过使用 onChange 事件完成的,该事件随后会更改上下文统计信息 key, value

但是,当控制台记录输出时。状态好像没有变化。

上下文是以下值的对象,默认情况下所有值为空。 更新后的上下文:

newSettings:
    anti_scam:
        enabled: null
        log_channel: null
        punishment_type: null

tmpSettings 对象

newSettings:
    anti_scam:
        enabled: true
        log_channel: null
        punishment_type: null

如您所见,enabled 的值已更改。但是反应上下文状态不是。这意味着该开关始终处于禁用状态或启用状态,具体取决于用户设置,并且他们无法更改它。

我试过的 最初我使用的是可变对象。但后来我发现有时这不会导致重新呈现页面的反应。所以,我转而制作一个不可变副本,并修改我希望从中更改的值。但这仍然没有解决问题。

非常感谢任何帮助。

const EnableSwitch = () => {
  const { context, setSaveEnabled } = useContext(SaveContext);
  const handleChange = (event) => {
    const tmpSettings = JSON.parse(JSON.stringify(context));
    tmpSettings.newSettings.anti_scam.enabled = event.target.checked;
    
    setSaveEnabled(tmpSettings);
  };

  return (
    <Fade bottom>
      <div>
        <Switch
          checked={context.newSettings.anti_scam.enabled}
          onChange={handleChange}
          inputProps={{ "aria-label": "controlled" }}
        />
      </div>
    </Fade>
  );
};

<SaveContext.Provider value={{ context, setSaveEnabled }}>

import { createContext } from "react";

const SaveContext = createContext({
    context: {
        saveEnabled: false,
        oldSettings: {
            anti_scam: {
                enabled: null,
                log_channel: null,
                punishment_type: null,
            }
        },
        newSettings: {
            anti_scam: {
                enabled: null,
                log_channel: null,
                punishment_type: null,
            }
        }
    },
    setSaveEnabled: () => { }
});

export const SaveProvider = SaveContext.Provider;
export default SaveContext;

上下文是一种从组件 A 到组件 B 获取值的方法,但它不会为您实现任何其他功能。如果您想将状态从组件 A 传递到组件 B,那么组件 A 将需要使用 useState 和其他此类代码来实现该状态。由于您只是使用默认值,因此 none 正在发生。

所以你需要在树的顶部附近制作一个组件,如下所示:

const Example = ({ children }) => {
  const [state, setState] = useState({
    saveEnabled: false,
    oldSettings: {
      anti_scam: {
        enabled: null,
        log_channel: null,
        punishment_type: null,
      },
    },
    newSettings: {
      anti_scam: {
        enabled: null,
        log_channel: null,
        punishment_type: null,
      },
    },
  });

  const contextValue = useMemo(() => {
    return {
      context: state,
      setSaveEnabled: /* some function which updates the state */,
    }
  }, [state]);

  return (
    <SaveContext.Provider value={contextValue}>
      {children}
    </SaveContext.Provider>
  )
};