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

时间:2018-08-06 18:52:47

标签: reactjs mobx mobx-react

我正在尝试基于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} />
}

component自变量按预期工作。但是我无法使props参数起作用。理想情况下,我会用它来构建类似的内容:

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

在一个示例中,<ChoosePostType />中的一个按钮可能会将main_area_sequence中的可观察值重新分配给上述内容。

有人知道如何将道具分配作为参数传递吗?

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

我怀疑您对此有误解。

回想一下,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获取道具,但我们还从name添加了this.props.name道具,并从onClick添加了this.handleClick道具。您可以想象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