当子组件调用父组件中的方法(函数)时,Mobx丢失状态(jsFiddle演示)

时间:2017-03-28 16:48:47

标签: mobx mobx-react

非常感谢任何帮助:

Mobx似乎在子组件和父组件之间失去状态。

我在下面制作了一个小提琴演示。包含注释和输出以便清晰。

(React,Mobx和Mobx-React的当前版本)

感谢。

JSFIDDLE DEMO HERE

https://jsfiddle.net/ymp1g6qk/3/

在此发现的展示

enter image description here

CONSOLE OUTPUT HERE

Console Output showing component life cycle and 'unassigned' upon event.

此处的示例代码:

const {observable, computed, extendObservable} = mobx;
const {observer} = mobxReact;
const {Component} = React;
const {render} = ReactDOM
const {autorun} = mobx

class MyItem {
  id = 0;
  @observable name = "";
  @observable selected = false;
  constructor(id, name, selected) {
    this.id = id;
    this.name = name;
    this.selected = selected;}
}



/* ESTIMATE STORE */
//  @observable <---- Observable not allowed. Generates "Not a Constructor Error"
class MyStore extends Component {

  @observable items = [];

  constructor() {
    super();

    this.items.push(new MyItem(1,  'copper'  ));
    this.items.push(new MyItem(10, 'Silver'  ));
    this.items.push(new MyItem(20, 'Gold'    ));
    this.items.push(new MyItem(30, 'Platinum'));
    this.items.push(new MyItem(40, 'Sapphire'));
    this.items.push(new MyItem(50, 'Diamond' ));

    console.log("finished with MyStore:", this.items, " with count: ", this.items.length, " items.");

  }

}
let MyItems = new MyStore();



@observer
class MyCard extends Component {
  constructor(props){
    super(props)
  }

  _toggle(e){
    console.log("... At (Child) Component");
    console.log("click event generates id:", e, "...and calls parent component function that was passed as a prop. (it succeeds)");
    this.props.onToggleSelection(e);

  }

  render() {

    return (
      <li onClick={this._toggle.bind(this, this.props.id )} className={(this.props.selected ? " selected" : "")}>
        <p>{this.props.name}</p>
      </li>
    )

  }
}


@observer
class Test extends Component {

  /* selections */
  item = 0;
  @observable selectedMyItems = [];

  @computed get itemsSelected() {
    return this.selectedMyItems.length;
  }

  constructor( props ){
    super( props );

  }


  componentWillReceiveProps(nextProps, nextContext) {
    console.log(" ...At panel will recieve props and selectedMyItems:", this.selectedMyItems.length);
  }





  componentDidMount() {
    console.log(" ...At DidMount, and selectedMyItems:", this.selectedMyItems.length);
  }


  shouldComponentUpdate(nextProps, nextState, nextContext) {
    console.log(" ...At ShouldUpdate, and selectedMyItems:", this.selectedMyItems.length);
    return null;
  }


  componentWillUpdate(nextProps, nextState, nextContext) {
    console.log(" ...At WillUpdate and selectedMyItems:", this.selectedMyItems.length);
  }


  componentDidUpdate(prevProps, prevState, prevContext) {
    console.log(" ...At DidUpdate and selectedMyItems:", this.selectedMyItems.length);
  }


  componentWillUnmount () {
    console.log(" ...At DidUnmount and selectedMyItems:", this.selectedMyItems.length);
  }


  toggleSelection(id){

    var itemindex = -1;

    console.log("...At (parent) _toggle selection:", id );

    /* find the clicked item */
    itemindex = MyItems.items.findIndex((MyItem =>  MyItem.id == id));

    console.log("...the id of the item is :", id);
    console.log("...the item's index is:", itemindex);
    console.log("...the record for that id is:", MyItems.items[itemindex]);
    console.log("...selected items array consists of:", this.selectedMyItems); // <<< Warning: "Undefined"
    console.log("...See??? The array is undefined:", this.selectedMyItems);

    /* toggle selected */
    MyItems.items[itemindex].selected = !MyItems.items[itemindex].selected; // <<< Succeeds.

    /* add or remove the selected item  */
    if ( MyItems.items[itemindex].selected ) {
      /* add the item to the list of selected items */
      console.log("...See??? The next line's push to the array fails: undefined:", this.selectedMyItems);
      this.selectedMyItems.push(id);                    // <<< ERROR: "Cannot read property 'push' of undefined"

    } else {
      /* remove the item from the list of selected items */
      this.selectedMyItems.splice(this.selectedMyItems.indexOf(id), 1); // <<< ERROR: "Cannot read property 'splice' of undefined"
    }

    // this.props.uistore.doCommand({cmd: "TOGGLE_PANEL_SELECTION", pld:{ panelname:"estimate", id: choice }});

  }

  render() {

    var i = 1;
    return (

      <div id="my-panel">
        Open the Console.<br/>
        Click on an item in the list to select or unselect it.<br/>
        Note that selectedMyItems is out of scope (unassigned).  Why?
        <ul className="">
          {MyItems.items.map(MyItem => {
            return (
              <MyCard key={i++} id={MyItem.id} name={MyItem.name} selected={MyItem.selected} tags={MyItem.tags} onToggleSelection={this.toggleSelection}/>
            )
          })}
        </ul>
        <ul className=""></ul>
      </div>

    );
  }
};

ReactDOM.render(<Test/>, app);

1 个答案:

答案 0 :(得分:0)

toggleSelection(id)中的方法class Test未绑定。

你应该在类Test构造函数(首选)中绑定它:

class Test extends Component {
    constructor() {
        this.toggleSelection = this.toggleSelection.bind(this);
    }

    ...
}

或“就地”绑定它:

<MyCard ... onToggleSelection={this.toggleSelection.bind(this)}/>

检查更新的jsFiddle版本:https://jsfiddle.net/ymp1g6qk/6/