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
- Creates and initializes a new project
- To create the required components, copy the HTML code, copy and import the CSS file
- 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