如何将 Mobx 商店作为道具传递给反应组件
How to pass Mobx store as props to react compoent
我有这个使用 mobx 的应用程序,其中有一个名为 "Listings" 的组件,它使用来自 mobx 的一些状态来呈现项目列表。
现在的方式是,Listings
组件通过使用 mobx 存储从其内部获取所需的数据(store.restaurantResults[store.selectedFood]
),如下所示:
const Listings = () => {
const store = React.useContext(StoreContext);
return useObserver(() => (
<div className="pa2">
{store.restaurantResults[store.selectedFood] &&
store.restaurantResults[store.selectedFood].map((rest, i) => {
return (
<div key={i} className="pa2 listing">
<p>{rest.name}</p>
</div>
);
})}
</div>
));
};
但我认为这是错误的,因为它将组件与数据耦合在一起,我想改为通过 props 传递该数据,以便它可以重用。
正确的做法是什么?现在我的 App
看起来像这样,它被包裹在 storeProvider
:
周围
function App() {
return (
<StoreProvider>
<div className="mw8 center">
<Header title="EasyLunch" subTitle="Find Pizza, Burgers or Sushi in Berlin the easy way"/>
<FixedMenu menuItem1={"Pizza"} menuItem2={"Burger"} menuItem3={"Sushi"} />
<p className="b tc pt3">or...</p>
<Search />
<Listings />
</div>
</StoreProvider>
);
}
我的想法是将 StoreProvider
中的所有内容提取到另一个具有商店的组件中,并通过 useObserver
returns jsx 以便我可以访问商店然后传递什么我需要作为其他组件的道具。像这样:
const Wapper = () => {
const store = React.useContext(StoreContext);
return useObserver(() => (
<div className="mw8 center">
<Header title="EasyLunch" subTitle="Find Pizza, Burgers or Sushi in Berlin the easy way" />
<FixedMenu menuItem1={"Pizza"} menuItem2={"Burger"} menuItem3={"Sushi"} />
<p className="b tc pt3">or...</p>
<Search />
<Listings listings={store.restaurantResults[store.selectedFood]} />
</div>
))
}
然后在 listings 组件上更改内部的硬编码 store.restaurantResults[store.selectedFood]
以使用现在传递的道具,即所谓的 listigs,如下所示:
const Listings = ({listings}) => {
const store = React.useContext(StoreContext);
return useObserver(() => (
store.loading
? <Loading />
: <div className="pa2">
<div className="flex flex-wrap">
{listings &&
listings.map((rest, i) => {
return (
<div key={i} className="pa2 listing">
<img className='object-fit' src={rest.image_url} alt="restuarant" />
<p>{rest.name}</p>
<p>{rest.location.address1}</p>
</div>
);
})}
</div>
</div>
));
};
这是有效的,但这是解决这个问题的正确方法吗?
我通常将我的商店定义为全局商店,因此每个组件都可以看到它:
class Store {
@observable myVar
}
global.store = new Store()
在我的组件中我只是使用它:
@observer
export default class MyComponent extends React.Component {
constructor () {
super()
store.myVar = 0
}
setMyVar (a) {
store.myVar += 1
}
render () {
return <button onClick={this.setMyVar}>
Clicked {store.myVar} times
</button>
}
}
由于 <Listings/>
可以与 listing
和 loading
一起提供,您可以:
const Listings = ({listings, loading}) => {
if(loading) return <Loading />
return (
<div className="pa2">
<div className="flex flex-wrap">
{listings && listings.map((rest, i) => {
return (
<div key={i} className="pa2 listing">
<img className='object-fit' src={rest.image_url} alt="restuarant" />
<p>{rest.name}</p>
<p>{rest.location.address1}</p>
</div>
);
})}
</div>
</div>
);
}
没有使用可观测值,不需要 useObservable
。
您想在 store
上 useObservables
列出列表,那么没有理由用 useObservable
包装所有组件。你应该只包装 <Listings/>
。
我有这个使用 mobx 的应用程序,其中有一个名为 "Listings" 的组件,它使用来自 mobx 的一些状态来呈现项目列表。
现在的方式是,Listings
组件通过使用 mobx 存储从其内部获取所需的数据(store.restaurantResults[store.selectedFood]
),如下所示:
const Listings = () => {
const store = React.useContext(StoreContext);
return useObserver(() => (
<div className="pa2">
{store.restaurantResults[store.selectedFood] &&
store.restaurantResults[store.selectedFood].map((rest, i) => {
return (
<div key={i} className="pa2 listing">
<p>{rest.name}</p>
</div>
);
})}
</div>
));
};
但我认为这是错误的,因为它将组件与数据耦合在一起,我想改为通过 props 传递该数据,以便它可以重用。
正确的做法是什么?现在我的 App
看起来像这样,它被包裹在 storeProvider
:
function App() {
return (
<StoreProvider>
<div className="mw8 center">
<Header title="EasyLunch" subTitle="Find Pizza, Burgers or Sushi in Berlin the easy way"/>
<FixedMenu menuItem1={"Pizza"} menuItem2={"Burger"} menuItem3={"Sushi"} />
<p className="b tc pt3">or...</p>
<Search />
<Listings />
</div>
</StoreProvider>
);
}
我的想法是将 StoreProvider
中的所有内容提取到另一个具有商店的组件中,并通过 useObserver
returns jsx 以便我可以访问商店然后传递什么我需要作为其他组件的道具。像这样:
const Wapper = () => {
const store = React.useContext(StoreContext);
return useObserver(() => (
<div className="mw8 center">
<Header title="EasyLunch" subTitle="Find Pizza, Burgers or Sushi in Berlin the easy way" />
<FixedMenu menuItem1={"Pizza"} menuItem2={"Burger"} menuItem3={"Sushi"} />
<p className="b tc pt3">or...</p>
<Search />
<Listings listings={store.restaurantResults[store.selectedFood]} />
</div>
))
}
然后在 listings 组件上更改内部的硬编码 store.restaurantResults[store.selectedFood]
以使用现在传递的道具,即所谓的 listigs,如下所示:
const Listings = ({listings}) => {
const store = React.useContext(StoreContext);
return useObserver(() => (
store.loading
? <Loading />
: <div className="pa2">
<div className="flex flex-wrap">
{listings &&
listings.map((rest, i) => {
return (
<div key={i} className="pa2 listing">
<img className='object-fit' src={rest.image_url} alt="restuarant" />
<p>{rest.name}</p>
<p>{rest.location.address1}</p>
</div>
);
})}
</div>
</div>
));
};
这是有效的,但这是解决这个问题的正确方法吗?
我通常将我的商店定义为全局商店,因此每个组件都可以看到它:
class Store {
@observable myVar
}
global.store = new Store()
在我的组件中我只是使用它:
@observer
export default class MyComponent extends React.Component {
constructor () {
super()
store.myVar = 0
}
setMyVar (a) {
store.myVar += 1
}
render () {
return <button onClick={this.setMyVar}>
Clicked {store.myVar} times
</button>
}
}
由于 <Listings/>
可以与 listing
和 loading
一起提供,您可以:
const Listings = ({listings, loading}) => {
if(loading) return <Loading />
return (
<div className="pa2">
<div className="flex flex-wrap">
{listings && listings.map((rest, i) => {
return (
<div key={i} className="pa2 listing">
<img className='object-fit' src={rest.image_url} alt="restuarant" />
<p>{rest.name}</p>
<p>{rest.location.address1}</p>
</div>
);
})}
</div>
</div>
);
}
没有使用可观测值,不需要 useObservable
。
您想在 store
上 useObservables
列出列表,那么没有理由用 useObservable
包装所有组件。你应该只包装 <Listings/>
。