如何将 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/> 可以与 listingloading 一起提供,您可以:

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

您想在 storeuseObservables 列出列表,那么没有理由用 useObservable 包装所有组件。你应该只包装 <Listings/>