将组件和道具作为参数传递

Passing component and props as arguments

我正在尝试根据 MobX 可观察值在 App.js 中呈现一个组件。我想定义一个采用组件和一些新的自定义道具分配的动作。这是我现在拥有的:

// App.js inside render()
{ ui_store.main_area_sequence }

.

// ui_store.js

// OBSERVABLES / state
main_area_sequence = <ChoosePostType />;

// ACTIONS / state mutators
update_ui_in_main_section(ComponentTag, props) {
    this.main_area_sequence = <ComponentTag {props} />
}

组件参数按预期工作。但是我无法使 props 参数起作用。理想情况下,我会用它来构建类似的东西:

<ChildComponentToBeSwitchedIn name={ui_store.name} handleClick={this.handleClick} /> 

<ChoosePostType /> 中的一个按钮可能会将 main_area_sequence 中的可观察值重新分配给上面的点击,举个例子。

有谁知道如何将 prop 赋值作为参数传递以便执行此操作?

如果您不传递 props,则不要包含 props 参数。

update_ui_in_main_section(ComponentTag) {
  this.main_area_sequence = <ComponentTag handleClick={this.handleClick} />;
}

我怀疑你想多了。

回想一下,JSX 只是 JavaScript。当您键入此内容时:

<Foo bar={123}>Baz!</Foo>

...你真的在写这个:

React.createElement(Foo, { bar: 123 }, 'Baz!');

但是,如果您要呈现的组件是动态的怎么办?没关系;它仍然有效。例如,假设我们将组件和道具保存在 React 组件的 state:

render() {
  return (
    <this.state.dynamicComponent
      {...this.state.dynamicComponentProps}
      name={this.props.name}
      onClick={this.handleClick}
    />
  );
}

上面的 JSX 翻译成这个 JavaScript:

React.createElement(this.state.dynamicComponent,
  { ...this.state.dynamicComponentProps,
    name: this.props.name,
    onClick: this.handleClick,
  }
);

如您所见,我们从 this.state.dynamicComponentProps 获得道具,但我们还添加了 this.props.namename 道具和 this.handleClickonClick 道具].你可以想象 this.handleClick 调用 this.setState 来更新 dynamicComponentdynamicComponentProps.

实际上,您不必想象它,因为您可以在下面的代码片段中看到它的工作原理:

class DynamicComponent extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.state = {
      dynamicComponent: ShowMeFirst,
      dynamicComponentProps: { style: { color: 'blue' }},
    };
  }
  
  render() {
    return (
      <this.state.dynamicComponent
        {...this.state.dynamicComponentProps}
        name={this.props.name}
        onClick={this.handleClick}
      />
    );
  }
  
  handleClick() {
    this.updateDynamicComponent(ShowMeSecond, { style: { color: 'red' }});
  }

  updateDynamicComponent(component, props) {
    this.setState({
      dynamicComponent: component,
      dynamicComponentProps: props,
    });
  }
}

const ShowMeFirst = ({ name, style, onClick }) => (
  <button type="button" style={style} onClick={onClick}>
    Hello, {name}!
  </button>
);

const ShowMeSecond = ({ name, style, onClick }) => (
  <button type="button" style={style} onClick={onClick}>
    Goodbye, {name}!
  </button>
);

ReactDOM.render(<DynamicComponent name="Alice"/>, document.querySelector('div'));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div></div>

我在上面使用了普通的旧 React 状态,但同样的事情也适用于 MobX,如下所示。 (我以前从未使用过 MobX,所以我的代码可能不够地道,但希望你能理解。)

const { action, decorate, observable } = mobx;
const { observer } = mobxReact;

class UIStore {
  dynamicComponent = ShowMeFirst;
  dynamicComponentProps = { style: { color: 'blue' }};
  
  updateDynamicComponent(component, props) {
    this.dynamicComponent = component;
    this.dynamicComponentProps = props;
  }
}

decorate(UIStore, {
  dynamicComponent: observable,
  dynamicComponentProps: observable,
  updateDynamicComponent: action,
});

const DynamicComponent = observer(({ store, name }) => (
  <store.dynamicComponent
    {...store.dynamicComponentProps}
    name={name}
    onClick={() =>
      store.updateDynamicComponent(ShowMeSecond, { style: { color: 'red' }})
    }
  />
));

const ShowMeFirst = ({ name, style, onClick }) => (
  <button type="button" style={{...style}} onClick={onClick}>
    Hello, {name}!
  </button>
);

const ShowMeSecond = ({ name, style, onClick }) => (
  <button type="button" style={{...style}} onClick={onClick}>
    Goodbye, {name}!
  </button>
);

ReactDOM.render(<DynamicComponent name="Alice" store={new UIStore()} />, document.querySelector('div'));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/mobx/lib/mobx.umd.js"></script>
<script src="https://unpkg.com/mobx-react@5.2.3/index.js"></script>
<div></div>

我不得不在这里使用 decorate,因为 Stack Overflow 的 Babel 配置不包括装饰器,但我在 CodeSandbox 上发布了与装饰器相同的东西:https://codesandbox.io/s/qlno63zkw4