簡體   English   中英

如何在不實際更改 state 的情況下重新渲染 React 組件

[英]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

有幾種方法可以處理這種情況。

  1. 在父組件中移動 state。 像這樣跟蹤父組件中的所有可見狀態:

  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}/> ) }
  1. 重置所有狀態后重置模式:
const [mode, setMode] = useState("hideAll") 
useEffect(() => {
   setMode("")
}, [mode])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM