2 回答

TA貢獻(xiàn)2041條經(jīng)驗(yàn) 獲得超4個(gè)贊
普通的 OOP 設(shè)計(jì)原則并不總是直接適用于 React 組件。組件通常沒有實(shí)例屬性,它們大多只有propsand state(有一些例外,您確實(shí)使用實(shí)例屬性,例如Animationreact-native中的對(duì)象,但這種情況很少見)。
你以一種在這里不太有意義的方式混合了這兩件事。 Settings是一個(gè)渲染圖像的 React 組件,但它也是一個(gè)通過調(diào)用 實(shí)例化的對(duì)象new Settings()。如果還有其他組件依賴于 的值flag,您可能希望將標(biāo)志的訪問和存儲(chǔ)與渲染組件分開,將值和回調(diào)傳遞給渲染器。
const Settings = ({setFlag}) => {
return(
<img src="./img/leaf.png" alt="" onClick={() => setFlag(true)}/>
);
}
您建議您喜歡Context API作為使值全局可用的解決方案flag。有幾種方法可以進(jìn)行設(shè)置,但這里是一種。
在任何組件之外,我們創(chuàng)建一個(gè)FlagContext具有兩個(gè)屬性的對(duì)象:boolean值flag和回調(diào)函數(shù)setFlag。我們需要給它一個(gè)默認(rèn)的后備值,希望永遠(yuǎn)不會(huì)使用該值,因此我們的默認(rèn)回調(diào)僅記錄警告而不執(zhí)行任何操作。
const FlagContext = createContext<FlagContextState>({
flag: false,
setFlag: () => console.warn("attempted to use FlagContext outside of a valid provider")
});
這個(gè)FlagContext對(duì)象放棄了Provider和Consumer組件,但是由我們來value給FlagContext.Provider. 因此,我們將創(chuàng)建一個(gè)處理該部分的自定義組件。我們的習(xí)慣FlagProvider使用本地狀態(tài)來創(chuàng)造和傳遞價(jià)值。我使用了函數(shù)組件,但您也可以使用類組件。
const FlagProvider = ({children}) => {
const [flag, setFlag] = useState(false);
return (
<FlagContext.Provider value={{
flag,
setFlag
}}>
{children}
</FlagContext.Provider>
)
}
我們希望將整個(gè)App放在里面,F(xiàn)lagProvider這樣整個(gè)App就有可能訪問flag和setFlag,并且整個(gè)App獲得相同的flag值。
當(dāng)您想要在組件中使用上下文中的值時(shí),可以使用鉤子useContext或Consumer組件。不管怎樣,我喜歡創(chuàng)建一個(gè)別名并導(dǎo)出它,而不是FlagContext直接導(dǎo)出對(duì)象。
export const FlagConsumer = FlagContext.Consumer;
export const useFlagContext = () => useContext(FlagContext);
對(duì)于Consumer,消費(fèi)者的子級(jí)是一個(gè)獲取上下文值的函數(shù),在特殊情況下是一個(gè)具有屬性flag和 的對(duì)象setFlag,并返回一些 JSX。
這通常是您內(nèi)聯(lián)定義的函數(shù):
const SomePage = () => {
return (
<FlagConsumer>
{({flag, setFlag}) => (<div>Flag Value is {flag.toString()}</div>)}
</FlagConsumer>
)
}
但它也可以是一個(gè)功能組件。請注意,當(dāng)使用函數(shù)組件作為子組件時(shí),必須傳遞組件本身 ( {Settings}) 而不是它的執(zhí)行版本 ( <Settings />)。
const Settings = ({ setFlag }) => {
return <img src="./img/leaf.png" alt="" onClick={() => setFlag(true)} />;
};
const SomePage = () => {
return <FlagConsumer>{Settings}</FlagConsumer>;
};
現(xiàn)在首選的方法是使用鉤子。我們useFlagContext()在函數(shù)組件的主體內(nèi)部調(diào)用,它返回我們的上下文對(duì)象。
const SomePage = () => {
const {flag, setFlag} = useFlagContext();
return <Settings setFlag={setFlag}/>
};
消費(fèi)者和鉤子只有在標(biāo)志上下文提供者內(nèi)部時(shí)才起作用,所以這就是我們將它放在整個(gè)應(yīng)用程序周圍的原因!
const App = () => {
return (
<FlagProvider>
<SomePage />
</FlagProvider>
);
};
CodeSandbox上的完整示例

TA貢獻(xiàn)1828條經(jīng)驗(yàn) 獲得超13個(gè)贊
對(duì)于這種交互,我強(qiáng)烈建議您使用Redux
我確信您會(huì)從中受益的另一個(gè)想法是切換到鉤子和功能組件:更少的樣板和更靈活的代碼。
回到目標(biāo),使用 Redux 您的代碼將類似于以下內(nèi)容:
const Settings = (props) => {
? const dispatch = useDispatch();
? const flag = useSelector(state => state.yourStoreObj.flag);
? ? ??
? handleClick() {
? ? dispatch(yourCustomAction("UPDATE_FLAG", true));
? }
??
? return(
? ? ? ? <img src="./img/leaf.png" alt="" onClick={() => handleClick()}/>
? ? );??
}
說明:
我們假設(shè)存儲(chǔ)中有一個(gè)屬性是該特定元素的“flag”屬性。通過這種方式,該屬性可以由組件本身使用useSelector()運(yùn)算符讀取,也可以在應(yīng)用程序中的任何位置使用相同的方法從任何其他組件讀取。
以同樣的方式,您可以通過分派更改來更改值(請參閱dispatch() 函數(shù)),并且以同樣的方式,您可以從任何其他組件執(zhí)行此操作。
因此,假設(shè)您想在完全不同的組件上發(fā)生單擊時(shí)更改該屬性,這就是其他組件的樣子
const OtherCoolComp = (props) => {
? const dispatch = useDispatch();
??
? handleClick() {
? ? dispatch(yourCustomAction("UPDATE_FLAG", true));
? }
??
? return(
? ? ? ? <button onClick={() => handleClick()}>
? ? ? ? ? Click me!
? ? ? ? </button>
? ? );??
}
因此,您從一個(gè)不知道誰在顯示該值的組件分派相同的操作,將其設(shè)置為您喜歡的值。
添加回答
舉報(bào)