Joseph Chambers
Joseph Chambers

Reputation: 4068

Compute mobx value from action

I'm currently refactoring a FreeCodeCamp repo as way to learn mobx. What I'm trying to do is calculate this.store.studentCount as you can see in the StudentModal Component. Take a look here:

This is my /client/src/components/students/Modal.js

@observer
@inject('StudentModal')
export default class StudentModal extends Component {

  store = new this.props.StudentModal()

  renderStudentCount() {
    let message
    if (this.store.studentCount > 1) {
      message = `${this.store.studentCount} students`
    } else {
      message = `${this.store.studentCount} student`
    }
    return <div id="student-count">{message}</div>
  }

  render() {
    return (
      <div className="AddStudentForm">
        <div className="class-table-button-container">
          <Button
            onClick={this.open}
          >
            Add Student
          </Button>
          {this.renderStudentCount()}
        </div>
        .....
    )
  }
}

Taking a look at my models for the Modal component you can see I need to fetch a service to get the length of this but for whatever reason I cannot set the studentCount to a new value.

This is my /client/src/models/students/Modal.js

import { observable, action } from 'mobx'
import StudentsService from '../../services/StudentsService'

export default class StudentModal {    
  @observable open = true

  @observable studentCount = 0

  @action
  fetchStudents() {
    StudentsService.fetchStudents().then(response => {
      const studentCount = response.body
      this.studentCount = studentCount.length
    })
  }
}

You can take a look at the full source code here: https://github.com/imcodingideas/classroom-mode/tree/mobx-migration which I should remind you that this is open-source.

Am I doing this correctly? Do you have any feedback for me?

Upvotes: 1

Views: 698

Answers (1)

Joel Harkes
Joel Harkes

Reputation: 11661

There seem to be some minor things:

Identical class names

This might lead to problems since, both your store and react component are called StudentModal

decorator order

as @Joseph suggested swap the order around your class:

@inject("StudentModal")
@observer
export default class StudentModal

State management

 store = new this.props.StudentModal()

On creation of every StudentModal you seem to create a new state store. Normally te store is instantiated once (unless you really want seperate stores per modal) inside your entry point and then used later on:

import { render } from "react-dom";
import { Provider } from "mobx-react";
var stores = { StudentModal: new StudanModalStore() }
render(
        <Provider {...stores}>
            <StudentModal />
        </Provider>,
    rootEl,
);

@observer
@inject('StudentModal')
export default class StudentModal extends Component {
    //used getter instead of setting once
    // no longer use `new` but directly reference instance of the store. 
    get store (): StudentModalStore { return this.props.StudentModalas; }

}

above code is in typescript.

Upvotes: 1

Related Questions