如何解决自定义钩子中的状态未更新
我无法从自定义挂钩获取更新状态。
这个例子很简单。这是一个自定义钩子,允许从暗主题切换到亮主题
在自定义钩子内,我使用 useMemo 返回一个记忆值,但每次我用 switchOn
更新状态时,这似乎都不会更新。
我不想在这个例子中使用上下文
import { useState,useMemo,useCallback } from "react";
const useTheme = (initial) => {
const [isOn,turnOn] = useState(false);
const switchOn = useCallback((e) => turnOn(e.target.checked),[turnOn]);
return useMemo(() => {
return {
theme: isOn ? "light" : "dark",buttonTheme: isOn ? "dark" : "light",lightsIsOn: isOn ? "On" : "Off",isChecked: isOn,switchOn,};
},[switchOn,isOn]);
};
export default useTheme;
import { useState,useRef,useReducer } from "react";
import useTheme from "./useTheme";
import todos from "./reducer";
import "./App.css";
const Item = ({ id,text,done,edit,remove }) => {
const { buttonTheme } = useTheme();
const isDone = done ? "done" : "";
return (
<div style={{ display: "flex" }}>
<li className={isDone} key={id} onClick={() => edit(id)}>
{text}
</li>
<button type="button" onClick={() => remove(id)} className={buttonTheme}>
<small>x</small>
</button>
</div>
);
};
const SwitchInput = () => {
const { switchOn,isChecked,lightsIsOn } = useTheme();
return (
<>
<label class="switch">
<input type="checkBox" onChange={switchOn} checked={isChecked} />
<span class="slider round"></span>
</label>
<span>
{" "}
Lights <b>{lightsIsOn}</b>
</span>
<br /> <br />
</>
);
};
const initialState = {
items: [],};
const init = (state) => {
return {
...state,items: [
{ id: 1,text: "Learning the hooks",done: false },{ id: 2,text: "Study JS",{ id: 3,text: "Buy conference ticket",],};
};
function App() {
const inputRef = useRef();
const [state,dispatch] = useReducer(todos,initialState,init);
const [inputValue,setInputValue] = useState(null);
const { theme } = useTheme();
const handleOnChange = (e) => setInputValue(e.target.value);
const handleOnSubmit = (e) => {
e.preventDefault();
dispatch({ type: "add",payload: inputValue });
inputRef.current.value = null;
};
return (
<div className={`App ${theme}`}>
<SwitchInput />
<form onSubmit={handleOnSubmit}>
<input ref={inputRef} type="text" onChange={handleOnChange} />
<ul>
{state.items.map((item) => (
<Item
{...item}
key={item.id}
remove={(id) => dispatch({ type: "remove",payload: { id } })}
edit={(id) => dispatch({ type: "edit",payload: { id } })}
/>
))}
</ul>
</form>
</div>
);
}
export default App;
我使用 App.css 来应用主题样式:深色和浅色
下面是一个演示。我们可以看到值没有改变
解决方法
您需要将 useTheme()
的值从 <App>
传递给 <SwitchInput>
才能共享,如下所示。
function App() {
const { theme,switchOn,isChecked,lightsIsOn } = useTheme();
return (
<div className={`App ${theme}`}>
<SwitchInput
switchOn={switchOn}
isChecked={isChecked}
lightsIsOn={lightsIsOn}
/>
</div>
);
}
然后,<SwitchInput>
将在道具中接收它们。
const SwitchInput = ({ switchOn,lightsIsOn }) => {
return (
<>
<label class="switch">
<input type="checkbox" onChange={switchOn} checked={isChecked} />
<span class="slider round"></span>
</label>
<span>
{" "}
Lights <b>{lightsIsOn}</b>
</span>
<br /> <br />
</>
);
};
在您的示例中,useTheme()
在 <App>
和 <SwitchInput>
中都被调用,但 theme
和其他值是单独初始化的,并且不会在每个组件之间共享。>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。