javascript - Component doesn't re-render when store updates - Mobx - Stack Overflow

I have three ponents; Form, Preview & AppStore. Clicking a button in Form adds an item to the store

I have three ponents; Form, Preview & AppStore. Clicking a button in Form adds an item to the store. This seems to work fine except that the list in the Preview ponent isn't updating/re-rendering when the store changes even though it has an @observer decorator. What am I missing?

Form has a button and handler function that adds an item to the store:

    @inject('AppStore')
    @observer class Form extends React.Component{

      handleAddItem= (item) =>{
        const {AppStore} = this.props;
        AppStore.addItem(item);
        console.log(AppStore.current.items)
      }

      render(){
        return(
              <button onClick={() => this.handleAddItem('Another Item')}>Add Item</button>

        )}
    }

Preview maps through the items (I'm using a drag and drop hoc so my code might look a bit odd)

  @inject('AppStore')
  @observer class Preview extends React.Component

...

return(
   <ul>
       {items.map((value, index) => (
        <SortableItem key={`item-${index}`} index={index} value={value} />
        ))}
  </ul>)

...

  return <SortableList items={AppStore.current.items} onSortEnd={this.onSortEnd} />;

Here is store:

import { observable, action, puted } from "mobx";

class AppStore {
  @observable other = {name: '', desc:'', items: [ 'item 1', 'item 2', 'item 3'], id:''}
  @observable current = {name: '', desc:'', items: [ 'item 1', 'item 2', 'item 3'], id:''}

  @action addItem = (item) => {
    this.current.items.push(item)
  }
}

const store = new AppStore();
export default store;

I have three ponents; Form, Preview & AppStore. Clicking a button in Form adds an item to the store. This seems to work fine except that the list in the Preview ponent isn't updating/re-rendering when the store changes even though it has an @observer decorator. What am I missing?

Form has a button and handler function that adds an item to the store:

    @inject('AppStore')
    @observer class Form extends React.Component{

      handleAddItem= (item) =>{
        const {AppStore} = this.props;
        AppStore.addItem(item);
        console.log(AppStore.current.items)
      }

      render(){
        return(
              <button onClick={() => this.handleAddItem('Another Item')}>Add Item</button>

        )}
    }

Preview maps through the items (I'm using a drag and drop hoc so my code might look a bit odd)

  @inject('AppStore')
  @observer class Preview extends React.Component

...

return(
   <ul>
       {items.map((value, index) => (
        <SortableItem key={`item-${index}`} index={index} value={value} />
        ))}
  </ul>)

...

  return <SortableList items={AppStore.current.items} onSortEnd={this.onSortEnd} />;

Here is store:

import { observable, action, puted } from "mobx";

class AppStore {
  @observable other = {name: '', desc:'', items: [ 'item 1', 'item 2', 'item 3'], id:''}
  @observable current = {name: '', desc:'', items: [ 'item 1', 'item 2', 'item 3'], id:''}

  @action addItem = (item) => {
    this.current.items.push(item)
  }
}

const store = new AppStore();
export default store;
Share Improve this question edited Dec 23, 2018 at 13:56 George Bleasdale asked Dec 22, 2018 at 13:55 George BleasdaleGeorge Bleasdale 3517 silver badges17 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

I'm fairly certain this is a case where MobX doesn't extend observability all the way down into your current.items array.

Objects in MobX will extend observability when first constructed/initialized -- so current.items is an observable property in the sense that if you changed it's value to some other primitive, your ponent would re-render.

For example:

current.items = 1; // changing it from your array to some totally new value
current.items = []; // this _might_ also work because it's a new array

Similarly, if AppStore had a top-level observable items that you were changing, then calling items.push() would also work.

class AppStore {
    @observable items = [];

    @action additem = (item) => {
        this.items.push(item);
    }
}

The problem in your case is that items is buried one level deep inside an observable object -- so pushing items into the current.items array isn't changing the value of the property in a way that MobX can detect.

It's admittedly very confusing, and the mon MobX pitfalls are sometimes hard to understand.

See also this line in the Object documentation:

Only plain objects will be made observable. For non-plain objects it is considered the responsibility of the constructor to initialize the observable properties.

Try to replace your action to be:

@action addItem = (item) => {
   this.current.items = this.current.items.concat([item]);
}

Here instead of using push for mutating the property, use concat which is used to merge two arrays and return a whole new array with a new reference that MobX can react to.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744400056a4572342.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信