在我的 React 应用程序中,我有一个名为 Value
的组件,它在 DOM 树的多个级别上有多个实例。它的值可以显示或隐藏,点击它可以显示或隐藏(如翻转卡片)。
我想制作 2 个按钮,“全部显示”和“全部隐藏”,这将使 Value
组件的所有这些实例显示或隐藏。我在一个组件(称为 Cases
)中创建了这些按钮,该组件是 Value
组件的每个实例的父级。它有一个名为 mode
的状态,单击按钮将其设置为“showAll”或“hideAll”。我使用 React Context 为 Value
组件提供这种选择的模式。
我的问题:在我单击“全部隐藏”按钮,然后通过单击使某些 Value
实例可见后,我无法再次隐藏所有这些实例。我猜是因为 Value 组件不会重新渲染,因为即使调用了 setMode("hideAll")
函数,它实际上并没有改变状态的值。
有没有办法在调用 Value
函数后重新渲染 setMode
实例,即使没有进行实际更改?
我对 React 和 Web 开发比较陌生,我不确定这是否是正确的方法,所以我也很乐意得到一些关于什么是更好的解决方案的建议。
这是我的组件的代码:
const ModeContext = React.createContext()
export default function Cases() {
const [mode, setMode] = useState("hideAll")
return (
<>
<div>
<button onClick={() => setMode("showAll")}>Show all answers</button>
<button onClick={() => setMode("hideAll")}>Hide all answers</button>
</div>
<ModeContext.Provider value={mode}>
<div>
{cases.map( item => <Case key={item.name} {...item}/> ) }
</div>
</ModeContext.Provider>
</>
)
}
export default function Value(props) {
const mode = useContext(ModeContext)
const [hidden, setHidden] = useState(mode === "showAll" ? false : true)
useEffect(() => {
if (mode === "showAll") setHidden(false)
else if (mode === "hideAll") setHidden(true)
}, [mode])
return (
hidden
? <span className="hiddenValue" onClick={() => setHidden(!hidden)}></span>
: <span className="value" onClick={() => setHidden(!hidden)}>{props.children}</span>
)
}
答案 0 :(得分:1)
首先需要创建上下文,然后才能将其用作提供者或用户。
因此请确保将此添加到文件的顶部。
const ModeContext = React.createContext('hideAll')
就目前而言,由于未创建 ModeContext
,因此 mode
组件中的 Value
应该未定义且永远不会更改。
如果您的组件位于单独的文件中,请确保同时导出 ModeContext
并将其导入到其他组件中。
这是组织一切并保持简单的一种方法。
// cases.js
const ModeContext = React.createContext('hideAll')
export default function Cases() {
const [mode, setMode] = useState("hideAll")
return (
<>
<div>
<button onClick={() => setMode("showAll")}>Show all answers</button>
<button onClick={() => setMode("hideAll")}>Hide all answers</button>
</div>
<ModeContext.Provider value={mode}>
<div>
{cases.map( item => <Case key={item.name} {...item}/> ) }
</div>
</ModeContext.Provider>
</>
)
}
export function useModeContext() {
return useContext(ModeContext)
}
// value.js
import { useModeContext } from './cases.js'
export default function Value(props) {
const mode = useContext(ModeContext)
const [hidden, setHidden] = useState(mode === "showAll" ? false : true)
useEffect(() => {
if (mode === "showAll") setHidden(false)
else if (mode === "hideAll") setHidden(true)
}, [mode])
return (
hidden
? <span className="hiddenValue" onClick={() => setHidden(!hidden)}></span>
: <span className="value" onClick={() => setHidden(!hidden)}>{props.children}</span>
)
}
附言我也犯过很多次这样的错误。
答案 1 :(得分:0)
您不应在 Value 组件中使用新状态。你的组件应该有一个 [only single of truth][1],在你的例子中是 mode
。在您的上下文中,您还应该提供一个隐藏组件的功能,您可以调用 setHidden
更改 Value 组件,如下所示:
export default function Value(props) {
const { mode, setHidden } = useContext(ModeContext)
if(mode === "showAll") {
return <span className="hiddenValue" onClick={() => setHidden("hideAll")}></span>
} else if(mode === "hideAll") {
return <span className="value" onClick={() => setHidden("showAll")}>{props.children}</span>
} else {
return null;
}
)
}
附言因为 mode
似乎是一个布尔值,所以您可以在 true 和 false 之间切换。
[1]:https://reactjs.org/docs/lifting-state-up.html
答案 2 :(得分:0)
有几种方法可以处理这种情况。
const [visible, setVisibilty] = useState(cases.map(() => true))
...
<button onClick={() => setVisibilty(casses.map(() => false)}>Hide all answers</button>
...
{cases.map((item, index) => <Case key={item.name} visible={visible[index]} {...item}/> ) }
const [mode, setMode] = useState("hideAll")
useEffect(() => {
setMode("")
}, [mode])