2 回答
TA贡献2041条经验 获得超4个赞
普通的 OOP 设计原则并不总是直接适用于 React 组件。组件通常没有实例属性,它们大多只有propsand state(有一些例外,您确实使用实例属性,例如Animationreact-native中的对象,但这种情况很少见)。
你以一种在这里不太有意义的方式混合了这两件事。 Settings是一个渲染图像的 React 组件,但它也是一个通过调用 实例化的对象new Settings()。如果还有其他组件依赖于 的值flag,您可能希望将标志的访问和存储与渲染组件分开,将值和回调传递给渲染器。
const Settings = ({setFlag}) => {
return(
<img src="./img/leaf.png" alt="" onClick={() => setFlag(true)}/>
);
}
您建议您喜欢Context API作为使值全局可用的解决方案flag。有几种方法可以进行设置,但这里是一种。
在任何组件之外,我们创建一个FlagContext具有两个属性的对象:boolean值flag和回调函数setFlag。我们需要给它一个默认的后备值,希望永远不会使用该值,因此我们的默认回调仅记录警告而不执行任何操作。
const FlagContext = createContext<FlagContextState>({
flag: false,
setFlag: () => console.warn("attempted to use FlagContext outside of a valid provider")
});
这个FlagContext对象放弃了Provider和Consumer组件,但是由我们来value给FlagContext.Provider. 因此,我们将创建一个处理该部分的自定义组件。我们的习惯FlagProvider使用本地状态来创造和传递价值。我使用了函数组件,但您也可以使用类组件。
const FlagProvider = ({children}) => {
const [flag, setFlag] = useState(false);
return (
<FlagContext.Provider value={{
flag,
setFlag
}}>
{children}
</FlagContext.Provider>
)
}
我们希望将整个App放在里面,FlagProvider这样整个App就有可能访问flag和setFlag,并且整个App获得相同的flag值。
当您想要在组件中使用上下文中的值时,可以使用钩子useContext或Consumer组件。不管怎样,我喜欢创建一个别名并导出它,而不是FlagContext直接导出对象。
export const FlagConsumer = FlagContext.Consumer;
export const useFlagContext = () => useContext(FlagContext);
对于Consumer,消费者的子级是一个获取上下文值的函数,在特殊情况下是一个具有属性flag和 的对象setFlag,并返回一些 JSX。
这通常是您内联定义的函数:
const SomePage = () => {
return (
<FlagConsumer>
{({flag, setFlag}) => (<div>Flag Value is {flag.toString()}</div>)}
</FlagConsumer>
)
}
但它也可以是一个功能组件。请注意,当使用函数组件作为子组件时,必须传递组件本身 ( {Settings}) 而不是它的执行版本 ( <Settings />)。
const Settings = ({ setFlag }) => {
return <img src="./img/leaf.png" alt="" onClick={() => setFlag(true)} />;
};
const SomePage = () => {
return <FlagConsumer>{Settings}</FlagConsumer>;
};
现在首选的方法是使用钩子。我们useFlagContext()在函数组件的主体内部调用,它返回我们的上下文对象。
const SomePage = () => {
const {flag, setFlag} = useFlagContext();
return <Settings setFlag={setFlag}/>
};
消费者和钩子只有在标志上下文提供者内部时才起作用,所以这就是我们将它放在整个应用程序周围的原因!
const App = () => {
return (
<FlagProvider>
<SomePage />
</FlagProvider>
);
};
CodeSandbox上的完整示例
TA贡献1828条经验 获得超13个赞
对于这种交互,我强烈建议您使用Redux
我确信您会从中受益的另一个想法是切换到钩子和功能组件:更少的样板和更灵活的代码。
回到目标,使用 Redux 您的代码将类似于以下内容:
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()}/>
);
}
说明:
我们假设存储中有一个属性是该特定元素的“flag”属性。通过这种方式,该属性可以由组件本身使用useSelector()运算符读取,也可以在应用程序中的任何位置使用相同的方法从任何其他组件读取。
以同样的方式,您可以通过分派更改来更改值(请参阅dispatch() 函数),并且以同样的方式,您可以从任何其他组件执行此操作。
因此,假设您想在完全不同的组件上发生单击时更改该属性,这就是其他组件的样子
const OtherCoolComp = (props) => {
const dispatch = useDispatch();
handleClick() {
dispatch(yourCustomAction("UPDATE_FLAG", true));
}
return(
<button onClick={() => handleClick()}>
Click me!
</button>
);
}
因此,您从一个不知道谁在显示该值的组件分派相同的操作,将其设置为您喜欢的值。
添加回答
举报