Note source: Hook Education – big front end employment Training camp

Content: Notes, thoughts and experiences in the process of learning

Tip: project actual combat article resources can not be uploaded, only for reference

The TOdo case for MobX

The preparatory work

  1. Creates and initializes a new project
  2. To create the required components, copy the HTML code, copy and import the CSS file
  3. Introduce three child components into the APP component

─ SRC

│ ├─ Components (New)

│ ├─ ├─ App.js

│ │ ├─ Fingers.js (New)

│ │ ├─ Header.js (New)

│ ├ ─ ├ ─ sci-molec.js

│ ├─ Index.CSS (New)

│ └ ─ index. Js

// SRC /components/ app.js introduces three child components

import Foot from './Foot'
import Header from './Header'
import Main from './Main'

function App() {
  return (
    <section className='todoapp'>
      <Header />
      <Main />
      <Foot />
    </section>)}export default App
Copy the code
// SRC /index.js introduces global CSS styles

import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App'
import './index.css'

ReactDOM.render(<App />.document.getElementById('root'))
Copy the code
// SRC /components/ header. js adds task components at the top

import React, { Component } from 'react'

export class Header extends Component {
  render() {
    return (
      <header className='header'>
        <h1>todos</h1>
        <input className='new-todo' placeholder='What needs to be done? ' />
      </header>)}}export default Header
Copy the code
// SRC /components/ main.js Task list displays components

import React, { Component } from 'react'

export class Main extends Component {
  render() {
    return (
      <section className='main'>
        <input className='toggle-all' type='checkbox' />
        <ul className='todo-list'>
          <li className='completed'>
            <div className='view'>
              <input className='toggle' type='checkbox' />
              <label>Taste JavaScript</label>
              <button className='destroy'></button>
            </div>
            <input className='edit' />
          </li>
          <li>
            <div className='view'>
              <input className='toggle' type='checkbox' />
              <label>Buy a unicorn</label>
              <button className='destroy'></button>
            </div>
            <input className='edit' />
          </li>
        </ul>
      </section>)}}export default Main
Copy the code
// SRC /components/ foot.js Bottom manipulation component

import React, { Component } from 'react'

export class Foot extends Component {
  render() {
    return (
      <footer className='footer'>
        <span className='todo-count'>
          <strong>0</strong> item left
        </span>
        <ul className='filters'>
          <li>
            <button className='selected'>All</button>
          </li>
          <li>
            <button>Active</button>
          </li>
          <li>
            <button>Completed</button>
          </li>
        </ul>

        <button className='clear-completed'>Clear completed</button>
      </footer>)}}export default Foot
Copy the code

Build a MobX workflow

  • Install modx and Mox-React dependencies

  • Create mobx-specific directories and files in the SRC directory

  • All three sub-components are needed to get through the mobx process

  • Note that the vscode editor needs to be configured with decorator syntax support

  • All of the following operations require careful use of modifiers

// SRC /MobX/todo.js creates a MobX repository

import { observable } from 'mobx'

/ / mobx class
class todoData {
  // Use modifiers to set the state to not be observed
  @observable list = 1
}

// Create an instance
const todoList = new todoData()
export default todoList
Copy the code
// SRC /index.js retrieves the repository and passes it on

import { Provider } from 'mobx-react'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App'
import './index.css'
import todoList from './MobX/todo'

ReactDOM.render(
  // Use the Provider to pass the repository
  <Provider todoList={todoList}>
    <App />
  </Provider>.document.getElementById('root'))Copy the code
// SRC /components/ Three child components are introduced into the state repository

import { inject, observer } from 'mobx-react'

/ / a decorator
@inject('todoList')
@observer
................
Copy the code

Implement task add function

  • Add event text box on top add event event on top, check whether enter key, whether not empty (trim)

  • Conditions are met to add the task content to the MOBX task list state

  • Clear the contents of the text box

// SRC /MobX/todo.js add task list, add task action

import { action, observable } from 'mobx'

/ / mobx class
class todoData {
  // Use modifiers to set the state to not be observed
  @observable list = []
  // Add a task
  @action.bound add(todo) {
    this.list.push(todo)
  }
}

// Create an instance
const todoList = new todoData()
export default todoList
Copy the code
// SRC /components/ header. js adds an event to the textbox

import { inject, observer } from 'mobx-react'
import React, { Component } from 'react'

/ / a decorator
@inject('todoList')
@observer
// Top component
class Header extends Component {
  // Task input box keyboard up event
  addtodo(e) {
    // Get the task name
    const name = e.target.value.trim()
    // Check the trigger condition
    if (e.key === 'Enter' && name.length > 0) {
      // Call action, passing parameters
      this.props.todoList.add({ name, completed: false })
      // Reset the input box
      e.target.value = ' '}}render() {
    return (
      <header className='header'>
        <h1>todos</h1>
        <input
          className='new-todo'
          placeholder='Write the task you want to add'// Add the keyboard lift eventonKeyUp={e= > this.addtodo(e)}
        />
      </header>)}}export default Header
Copy the code

Achieve task list display function

  • You can start by writing some virtual data

  • The list component retrieves all tasks for data traversal binding

// SRC /MobX/todo.js write some test data

import { action, observable } from 'mobx'

/ / mobx class
class todoData {
  // Use modifiers to set the state to be unobservable, write some virtual data
  @observable list = [
    { name: 'eat'.completed: false },
    { name: 'sleep'.completed: false },
    { name: 'Beat the beans'.completed: true},]// Add a task
  @action.bound add(todo) {
    this.list.push(todo)
  }
}

// Create an instance
const todoList = new todoData()
export default todoList
Copy the code
// SRC /components/ main.js uses the obtained state data to create a structure to display

import { inject, observer } from 'mobx-react'
import React, { Component } from 'react'

/ / a decorator
@inject('todoList')
@observer
// Intermediate list component
class Main extends Component {
  render() {
    // Deconstruct the object
    const { todoList } = this.props
    return (
      <section className='main'>
        <input className='toggle-all' type='checkbox' />
        <ul className='todo-list'>Todolist.list. map((todo, index) => (// dynamically set the class name<li className={todo.completed ? 'completed' :"'}key={index}>
              <div className='view'>
                <input className='toggle' type='checkbox' />
                <label>{todo.name}</label>
                <button className='destroy'></button>
              </div>
              <input className='edit' />
            </li>
          ))}
        </ul>
      </section>)}}export default Main
Copy the code

The deletion task function is implemented

  • Click the delete button to trigger the event, invoke the action of the delete task, and pass the parameters
// SRC /MobX/todo.js add delete time action
// Delete the task
  @action.bound remove(index) {
    this.list.splice(index, 1)}// SRC /components/ main.js adds the click event to the delete button to trigger the delete action directly
<button
  className='destroy'
  // Add click event delete task, call action directly
  onClick={() = > todoList.remove(index)}>
</button>
Copy the code

Realizes the function of switching the task completion status

  • The event is triggered when the checkbox in front of the task is clicked, the action that changes the state is invoked, and the parameters are passed
// SRC /MobX/todo.js add and modify the task status action
// Change the task status
@action.bound changeCompleted(index, state) {
  this.list[index].completed = state
}

// SRC /components/ main. js Set dynamic display of task status, add status change event directly trigger action
<input
  className='toggle'
  type='checkbox'
  // Dynamically set the selected state
  defaultChecked={todo.completed ? true : false}
  // Add event to trigger action directly
  onChange={e= >
    todoList.changeCompleted(index, e.target.checked)
  }
/>
Copy the code

Count the number of unfinished tasks

  • Using mobx’s calculated value, count the number of unfinished tasks and bind it to the bottom count
// SRC /MobX/todo.js adds calculated values to calculate unfinished tasks
// Count unfinished tasks
@computed get completedNum() {
  return this.list.filter(item= > item.completed === false).length
}

// SRC /components/ foot.js binding computes value data
<span className='todo-count'>
  {/* Bind the mobx calculated value */}
  <strong>{this.props.todoList.completedNum}</strong> item left
</span>
Copy the code

Achieve task filtering function

  • You also need to add a filter tag state using the Mobx calculated value functionality

  • Clicking on a filter condition triggers an action to modify the condition

  • Filter out the corresponding display list according to the filter tag

  • Finally, the list data of the original display task is converted into the calculated value after filtering

  • The three filter buttons set the class name based on the filter state

// SRC /MobX/todo.js adds filter calculation values, filter action and filter status values

import { action, computed, observable } from 'mobx'

/ / mobx class
class todoData {
  // Use modifiers to set the state to be unobservable, write some virtual data
  @observable list = [
    { name: 'eat'.completed: false },
    { name: 'sleep'.completed: false },
    { name: 'Beat the beans'.completed: true},]// Filter criteria
  @observable filterName = 'All'
  // Add a task
  @action.bound add(todo) {
    this.list.push(todo)
  }
  // Delete the task
  @action.bound remove(index) {
    this.list.splice(index, 1)}// Change the task status
  @action.bound changeCompleted(index, state) {
    this.list[index].completed = state
  }
  // Count unfinished tasks
  @computed get completedNum() {
    return this.list.filter(item= > item.completed === false).length
  }
  // Calculated values - filter by condition
  @computed get filterList() {
    switch (this.filterName) {
      case 'all':
        return this.list
      case 'Active':
        return this.list.filter(item= > item.completed === false)
      case 'Completed':
        return this.list.filter(item= > item.completed === true)
      default:
        return this.list
    }
  }
  // Modify the filter criteria
  @action.bound changeFilterName(name) {
    this.filterName = name
  }
}

// Create an instance
const todoList = new todoData()
export default todoList
Copy the code
// SRC /components/ foot.js three filters add click events and dynamically set the class name

import { inject, observer } from 'mobx-react'
import React, { Component } from 'react'

/ / a decorator
@inject('todoList')
@observer
// Bottom component
class Foot extends Component {
  render() {
    return (
      <footer className='footer'>
        <span className='todo-count'>{/* Bind the mobx calculated value */}<strong>{this.props.todoList.completedNum}</strong> item left
        </span>
        <ul className='filters'>{/* Three filter buttons add click events. Trigger action to modify filter */}<li onClick={()= > this.props.todoList.changeFilterName('All')}>
            <button// Three buttons to dynamically set the class nameclassName={
                this.props.todoList.filterName= = ='All' ? 'selected' :"'} >
              All
            </button>
          </li>
          <li onClick={()= > this.props.todoList.changeFilterName('Active')}>
            <button
              className={
                this.props.todoList.filterName= = ='Active' ? 'selected' :"'} >
              Active
            </button>
          </li>
          <li onClick={()= > this.props.todoList.changeFilterName('Completed')}>
            <button
              className={
                this.props.todoList.filterName= = ='Completed' ? 'selected' :"'} >
              Completed
            </button>
          </li>
        </ul>
        <button className='clear-completed'>Clear completed</button>
      </footer>)}}export default Foot
Copy the code
// SRC /components/ main.js shows the data changed to filtered data - calculated values

import { inject, observer } from 'mobx-react'
import React, { Component } from 'react'

/ / a decorator
@inject('todoList')
@observer
// Intermediate list component
class Main extends Component {
  render() {
    // Deconstruct the object
    const { todoList } = this.props
    return (
      <section className='main'>
        <input className='toggle-all' type='checkbox' />
        <ul className='todo-list'>Todolist.filterlist. map((todo, index) => (// dynamically set the class name<li className={todo.completed ? 'completed' :"'}key={index}>
              <div className='view'>
                <input
                  className='toggle'
                  type='checkbox'// Dynamically set the selected statedefaultChecked={todo.completed ? true : false} // Add an event, which is triggered directlyaction
                  onChange={e= >
                    todoList.changeCompleted(index, e.target.checked)
                  }
                />
                <label>{todo.name}</label>
                <button
                  className='destroy'// Add click event delete task, called directlyaction
                  onClick={()= > todoList.remove(index)}></button>
              </div>
              <input className='edit' />
            </li>
          ))}
        </ul>
      </section>)}}export default Main

Copy the code

At the end

The course project is over, but there are still some bugs that can be fixed, such as an error when changing the status of a non-all filter