Состояние потери Mobx, когда дочерний компонент вызывает метод (функцию) в родительском компоненте (демонстрация jsFiddle)

Любая помощь высоко ценится:

Mobx, похоже, теряет состояние между дочерними и родительскими компонентами.

Я сделал демонстрацию Fiddle ниже. Включает комментарии и вывод для ясности.

(Текущие версии React, Mobx и Mobx-React)

Спасибо.

ДЕМО JSFIDDLE ЗДЕСЬ

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

СКРИНШОТ ДЕМО ЗДЕСЬ

введите здесь описание изображения

ВЫВОД В КОНСОЛЬ ЗДЕСЬ

Вывод консоли, показывающий жизненный цикл компонента и

ПРИМЕР КОДА ЗДЕСЬ:

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);

person Curt Doolittle    schedule 28.03.2017    source источник
comment
Observable not allowed. Generates "Not a Constructor Error". Вы должны использовать декоратор @observer, а не @observable при превращении компонента в наблюдателя.   -  person Tholle    schedule 29.03.2017
comment
это не наблюдатель. Это заметно. это магазин.   -  person Curt Doolittle    schedule 29.03.2017
comment
Ты прав. Извини за это. Нет необходимости помещать какой-либо декоратор в сам класс хранилища.   -  person Tholle    schedule 29.03.2017


Ответы (1)


Метод toggleSelection(id) в class Test не был связан.

Вы должны связать его в конструкторе тестов класса (предпочтительно):

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

    ...
}

или привяжите его «на место»:

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

Проверьте обновленную версию jsFiddle: https://jsfiddle.net/ymp1g6qk/6/

person Petr    schedule 14.04.2017