![](/img/trans.png)
[英]React re-render conditional on state change without changing the conditional
[英]How to re-render React components without actually changing state
在我的 React 應用程序中,我有一個名為Value
的組件,它在 DOM 樹的多個級別上有多個實例。 它的值可以顯示或隱藏,通過單擊它,它會顯示或隱藏(如翻轉卡片)。
我想制作 2 個按鈕,“全部顯示”和“全部隱藏”,這將使Value
組件的所有這些實例顯示或隱藏。 我在一個組件(稱為Cases
)中創建了這些按鈕,該組件是Value
組件的每個實例的父級。 它有一個名為mode
的 state ,單擊按鈕將其設置為“showAll”或“hideAll”。 我使用 React Context 將這個選擇的模式提供給Value
組件。
我的問題:單擊“全部隱藏”按鈕,然后通過單擊它們使一些Value
實例可見后,我無法再次隱藏所有這些實例。 我猜這是因為 Value 組件不會重新渲染,因為即使調用了setMode("hideAll")
function,它實際上並沒有改變 state 的值。
有沒有辦法在調用setMode
function 后重新渲染Value
實例,即使沒有進行實際更改? 我對 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>
)
}
您首先需要創建上下文,然后才能將其用作提供者或用戶。
因此,請確保將其添加到文件的頂部。
const ModeContext = React.createContext('hideAll')
就目前而言,由於未創建ModeContext
,因此您的Value
組件中的mode
應該是未定義的並且永遠不會改變。
如果您的組件位於單獨的文件中,請確保同時導出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>
)
}
PS我也犯過很多次這個錯誤。
您不應在 Value 組件中使用新的 state。 你的組件應該有一個[唯一的事實][1],在你的情況下是mode
。 在您的上下文中,您還應該提供一個 function 來隱藏組件,您可以調用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;
}
)
}
PS 因為mode
好像是 boolean 值,所以可以在真假之間切換。 [1]: https://reactjs.org/docs/lifting-state-up.html
有幾種方法可以處理這種情況。
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])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.