React + IndexDb + рдСрдЯреЛ-рдЕрдкрдбреЗрдЯ = рд▓рдЧрднрдЧ AsyncRedux

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рдЖрдкрдХреЛ рдХрджрдо рд╕реЗ рдХрджрдо рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рдХреИрд╕реЗ ReactJS рдореЗрдВ рд▓рд┐рдЦреА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП IndexDB (рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдЬреЛ рдХрд┐рд╕реА рднреА рдЖрдзреБрдирд┐рдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ) рддреИрдпрд╛рд░ рдХрд░рдирд╛ рд╣реИред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдЖрдк рдЗрдВрдбреЗрдХреНрд╕рдбреАрдмреА рд╕реЗ рдбреЗрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЖрд╕рд╛рдиреА рд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреИрд╕реЗ рдХрд┐ рдпрд╣ рдЖрдкрдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ Redux рд╕реНрдЯреЛрд░ рдореЗрдВ рдерд╛ ред

IndexDB рдПрдХ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝- рдЙрдиреНрдореБрдЦ DBMS рд╣реИ, рдЬреЛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреА рдУрд░ рд╕рдВрд░рдЪрд┐рдд рдбреЗрдЯрд╛ рдХреА рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рдЫреЛрдЯреА рд░рд╛рд╢рд┐ (рдЗрдХрд╛рдЗрдпреЛрдВ рдФрд░ рдореЗрдЧрд╛рдмрд╛рдЗрдЯреНрд╕ рдХреЗ рджрд╕рд┐рдпреЛрдВ) рдХреЗ рдЕрд╕реНрдерд╛рдпреА рднрдВрдбрд╛рд░рдг рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдЙрдкрдХрд░рдг рд╣реИред рдЬрд┐рд╕ рдорд╛рдирдХ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ IndexDB рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИ, рдЙрд╕рдореЗрдВ рдЧреНрд░рд╛рд╣рдХ рдкрдХреНрд╖ рдкрд░ рд╡реНрдпрд╛рдкрд╛рд░ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛рдУрдВ рдХреЗ рдбреЗрдЯрд╛ (рджреЗрд╢реЛрдВ, рд╢рд╣рд░реЛрдВ, рдХреЛрдб рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдореБрджреНрд░рд╛рдПрдВ, рдЖрджрд┐) рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рдХреНрд▓рд╛рдЗрдВрдЯ рд╕рд╛рдЗрдб рдореЗрдВ рдЙрдиреНрд╣реЗрдВ рдХреЙрдкреА рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдЖрдк рдХреЗрд╡рд▓ рд╕рд░реНрд╡рд░ (рдпрд╛ рд╕рдВрдкреВрд░реНрдг - рд╡реЗ рдЫреЛрдЯреЗ рд╣реИрдВ) рд╕реЗ рдЗрди рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛рдУрдВ рд╕реЗ рдЕрдкрдбреЗрдЯ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╣рд░ рдмрд╛рд░ рдЬрдм рдЖрдк рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╡рд┐рдВрдбреЛ рдЦреЛрд▓рддреЗ рд╣реИрдВ рддреЛ рдРрд╕рд╛ рди рдХрд░реЗрдВред

IndexDB рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЧреИрд░-рдорд╛рдирдХ, рдмрд╣реБрдд рд╡рд┐рд╡рд╛рджрд╛рд╕реНрдкрдж, рд▓реЗрдХрд┐рди рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рд╣реИрдВ:

  • рд╕рднреА рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рд╡рд╕реНрддреБрдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рдХреИрд╢рд┐рдВрдЧ рдХрд░рдирд╛ рддрд╛рдХрд┐ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕рд╛рдЗрдб рдкрд░ рд╡реНрдпрд╛рдкрдХ рдЫрдВрдЯрд╛рдИ рдФрд░ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХреНрд╖рдорддрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣реЛ
  • Redux рд╕реНрдЯреЛрд░ рдХреЗ рдмрдЬрд╛рдп IndexDB рдореЗрдВ рдЖрд╡реЗрджрди рдХреА рд╕реНрдерд┐рддрд┐

IndexDB рдФрд░ Redux Store рдХреЗ рдмреАрдЪ рддреАрди рдкреНрд░рдореБрдЦ рдЕрдВрддрд░ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИрдВ:

  1. IndexDB рдПрдХ рдмрд╛рд╣рд░реА рд╕рдВрдЧреНрд░рд╣рдг рд╣реИ рдЬрд┐рд╕реЗ рдкреГрд╖реНрда рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рддреЗ рд╕рдордп рд╕рд╛рдлрд╝ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рдХрдИ рдЦреБрд▓реЗ рдЯреИрдм рдХреЗ рд▓рд┐рдП рд╕рдорд╛рди рд╣реИ (рдЬреЛ рдХрднреА-рдХрднреА рдХреБрдЫ рдЕрдкреНрд░рддреНрдпрд╛рд╢рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рдУрд░ рдЬрд╛рддрд╛ рд╣реИ)
  2. IndexDB рдПрдХ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ DBMS рд╣реИред рд╕рднреА рдСрдкрд░реЗрд╢рди - рдЦреЛрд▓рдирд╛, рдкрдврд╝рдирд╛, рд▓рд┐рдЦрдирд╛, рдЦреЛрдЬрдирд╛ - рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХред
  3. IndexDB JSON рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд (рддреБрдЪреНрдЫ рддрд░реАрдХреЗ рд╕реЗ) рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рд╕реНрдиреИрдкрд╢реЙрдЯ рдмрдирд╛рдиреЗ, рдбреАрдмрдЧ рдХрд░рдиреЗ рдореЗрдВ рдЖрд╕рд╛рдиреА рдФрд░ рдЕрддреАрдд рдореЗрдВ рдпрд╛рддреНрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Redux рд╕реЗ рдорд╕реНрддрд┐рд╖реНрдХ-рдЪрд╛рд▓рд┐рдд рддрдХрдиреАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдЪрд░рдг 0: рдХрд╛рд░реНрдп рд╕реВрдЪреА


рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрд╛рд░реНрдпреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдХреЗ рд╕рд╛рде рдПрдХ рдХреНрд▓рд╛рд╕рд┐рдХ рдЙрджрд╛рд╣рд░рдгред рд╡рд░реНрддрдорд╛рди рдФрд░ рдПрдХрдорд╛рддреНрд░ рдШрдЯрдХ рдХреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд░рд╛рдЬреНрдп рдХреЗ рднрдВрдбрд╛рд░рдг рдХреЗ рд╕рд╛рде рднрд┐рдиреНрдирддрд╛

рдХрд┐рд╕реА рдХрд╛рд░реНрдп рд╕реВрдЪреА рдШрдЯрдХ рдХреЗ рдШрдЯрдХ рд░рд╛рдЬреНрдп рдореЗрдВ рд╕реВрдЪреА рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
import React, { PureComponent } from 'react'; import Button from 'react-bootstrap/Button'; import counter from 'common/counter'; import Form from 'react-bootstrap/Form'; import Table from 'react-bootstrap/Table'; export default class Step0 extends PureComponent { constructor() { super( ...arguments ); this.state = { newTaskText: '', tasks: [ { id: counter(), text: 'Sample task' }, ], }; this.handleAdd = () => { this.setState( state => ( { tasks: [ ...state.tasks, { id: counter(), text: state.newTaskText } ], newTaskText: '', } ) ); }; this.handleDeleteF = idToDelete => () => this.setState( state => ( { tasks: state.tasks.filter( ( { id } ) => id !== idToDelete ), } ) ); this.handleNewTaskTextChange = ( { target: { value } } ) => this.setState( { newTaskText: value || '', } ); } render() { return <Table bordered hover striped> <thead><tr> <th>#</th><th>Text</th><th /> </tr></thead> <tbody> { this.state.tasks.map( task => <tr key={task.id}> <td>{task.id}</td> <td>{task.text}</td> <td><Button onClick={this.handleDeleteF( task.id )} type="button" variant="danger"></Button></td> </tr> ) } <tr key="+1"> <td /> <td><Form.Control onChange={this.handleNewTaskTextChange} placeholder="  " type="text" value={this.state.newTaskText || ''} /></td> <td><Button onClick={this.handleAdd} type="button" variant="primary"></Button></td> </tr> </tbody> </Table>; } } 
( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдЕрдм рддрдХ, рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рд╕рднреА рдСрдкрд░реЗрд╢рди рд╕рд┐рдВрдХреНрд░реЛрдирд╕ рд╣реИрдВред рдпрджрд┐ рдХрд┐рд╕реА рдХрд╛рд░реНрдп рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдореЗрдВ 3 рд╕реЗрдХрдВрдб рд▓рдЧрддреЗ рд╣реИрдВ, рддреЛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдмрд╕ 3 рд╕реЗрдХрдВрдб рдХреЗ рд▓рд┐рдП рдлреНрд░реАрдЬ рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рдмреЗрд╢рдХ, рдЬрдм рд╣рдо рдЕрдкрдиреА рдпрд╛рджрджрд╛рд╢реНрдд рдореЗрдВ рд╕рдм рдХреБрдЫ рд░рдЦрддреЗ рд╣реИрдВ, рд╣рдо рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд╣реАрдВ рд╕реЛрдЪ рд╕рдХрддреЗред рдЬрдм рд╣рдо рдХрд┐рд╕реА рд╕рд░реНрд╡рд░ рдпрд╛ рдХрд┐рд╕реА рд╕реНрдерд╛рдиреАрдп рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХреЗ рд╕реБрдВрджрд░ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд╕рд╛рде-рд╕рд╛рде рджреЗрдЦрднрд╛рд▓ рднреА рдХрд░рдиреА рд╣реЛрдЧреАред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рддрддреНрд╡реЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдпрд╛ рд╣рдЯрд╛рдиреЗ рдХреЗ рджреМрд░рд╛рди рдПрдХ рддрд╛рд▓рд┐рдХрд╛ (рдпрд╛ рд╡реНрдпрдХреНрддрд┐рдЧрдд рддрддреНрд╡реЛрдВ) рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХреЛ рдЕрд╡рд░реБрджреНрдз рдХрд░рдирд╛ред

рднрд╡рд┐рд╖реНрдп рдореЗрдВ UI рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЛ рдирд╣реАрдВ рджреЛрд╣рд░рд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЗрд╕реЗ рдПрдХ рдЕрд▓рдЧ рдХрд╛рд░реНрдпрд╕реВрдЪреА рдШрдЯрдХ рдореЗрдВ рд░рдЦреЗрдВрдЧреЗ, рдЬрд┐рд╕рдХрд╛ рдПрдХрдорд╛рддреНрд░ рдХрд╛рд░реНрдп рдХрд╛рд░реНрдп рд╕реВрдЪреА рдХрд╛ HTML рдХреЛрдб рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧрд╛ред рдЙрд╕реА рд╕рдордп, рд╣рдо рд╕рд╛рдорд╛рдиреНрдп рдмрдЯрди рдХреЛ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдмрдЯрди рдХреЗ рдЪрд╛рд░реЛрдВ рдУрд░ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдЖрд╡рд░рдг рдХреЗ рд╕рд╛рде рдмрджрд▓ рджреЗрдВрдЧреЗ, рдЬреЛ рдмрдЯрди рдХреЛ рддрдм рддрдХ рдЕрд╡рд░реБрджреНрдз рдХрд░реЗрдЧрд╛ рдЬрдм рддрдХ рдХрд┐ рдмрдЯрди рд╣реИрдВрдбрд▓рд░ рдЕрдкрдиреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЛ рдкреВрд░рд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рднрд▓реЗ рд╣реА рдпрд╣ рд╣реИрдВрдбрд▓рд░ рдПрдХ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдлрд╝рдВрдХреНрд╢рди рд╣реЛред

рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдХрд╛рд░реНрдп рд╕реВрдЪреА рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдПрдХ рдШрдЯрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛
 import React, { PureComponent } from 'react'; import counter from 'common/counter'; import TaskList from '../common/TaskList'; export default class Step01 extends PureComponent { constructor() { super( ...arguments ); this.state = { tasks: [ { id: counter(), text: 'Sample task' }, ] }; this.handleAdd = newTaskText => { this.setState( state => ( { tasks: [ ...state.tasks, { id: counter(), text: newTaskText } ], } ) ); }; this.handleDelete = idToDelete => this.setState( state => ( { tasks: state.tasks.filter( ( { id } ) => id !== idToDelete ), } ) ); } render() { return <> <h1>      </h1> <h2>       </h2> <TaskList onAdd={this.handleAdd} onDelete={this.handleDelete} tasks={this.state.tasks} /> </>; } } 
( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдПрдХ рдШрдЯрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЬреЛ рдХрд╛рд░реНрдпреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдПрдХ рдирдпрд╛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлреЙрд░реНрдо рд╣реЛрддрд╛ рд╣реИ
 import React, { PureComponent } from 'react'; import Button from './AutoDisableButtonWithSpinner'; import Form from 'react-bootstrap/Form'; import Table from 'react-bootstrap/Table'; export default class TaskList extends PureComponent { constructor() { super( ...arguments ); this.state = { newTaskAdding: false, newTaskText: '', }; this.handleAdd = async() => { this.setState( { newTaskAdding: true } ); try { //   ,     await this.props.onAdd( this.state.newTaskText ); this.setState( { newTaskText: '' } ); } finally { this.setState( { newTaskAdding: false } ); } }; this.handleDeleteF = idToDelete => async() => await this.props.onDelete( idToDelete ); this.handleNewTaskTextChange = ( { target: { value } } ) => this.setState( { newTaskText: value || '', } ); } render() { return <Table bordered hover striped> <thead><tr> <th>#</th><th>Text</th><th /> </tr></thead> <tbody> { this.props.tasks.map( task => <tr key={task.id}> <td>{task.id}</td> <td>{task.text}</td> <td><Button onClick={this.handleDeleteF( task.id )} type="button" variant="danger"></Button></td> </tr> ) } <tr key="+1"> <td /> <td><Form.Control disabled={this.state.newTaskAdding} onChange={this.handleNewTaskTextChange} placeholder="  " type="text" value={this.state.newTaskText || ''} /></td> <td><Button onClick={this.handleAdd} type="button" variant="primary"></Button></td> </tr> </tbody> </Table>; } } 
( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдирдореВрдирд╛ рдХреЛрдб рдореЗрдВ рдЖрдк рдХреАрд╡рд░реНрдб async / рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред Async / рдкреНрд░рддреАрдХреНрд╖рд╛рд░рдд рдирд┐рд░реНрдорд╛рдг рдХреЛрдб рдХреА рдорд╛рддреНрд░рд╛ рдХреЛ рдХрдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рд╡рд╛рджреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдкреНрд░рддреАрдХреНрд╖рд┐рдд рдХреАрд╡рд░реНрдб рдЖрдкрдХреЛ рдкреНрд░реЛрдорд┐рд╕ рд▓реМрдЯрд╛рдиреЗ рд╡рд╛рд▓реЗ рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЬреИрд╕реЗ рдХрд┐ рдпрд╣ рдПрдХ рдирд┐рдпрдорд┐рдд рдлрд╝рдВрдХреНрд╢рди рдерд╛ (рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рддрдм () рдореЗрдВ рдкрд░рд┐рдгрд╛рдо рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣рд╛ рд╣реИ)ред рдмреЗрд╢рдХ, рдПрдХ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдлрд╝рдВрдХреНрд╢рди рдЬрд╛рджреБрдИ рд░реВрдк рд╕реЗ рдПрдХ рд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдореЗрдВ рдирд╣реАрдВ рдмрджрд▓рддрд╛ рд╣реИ, рдФрд░, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдирд┐рд╖реНрдкрд╛рджрди рдереНрд░реЗрдб рдХреЛ рдмрд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬрдм рд╡реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рддрдм рдХреЛрдб рдЕрдзрд┐рдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдФрд░ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ, рдФрд░ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рд▓реВрдк рдореЗрдВ рдФрд░ рдХреЛрд╢рд┐рд╢ / рдкрдХрдбрд╝рдиреЗ / рдЕрдВрдд рдореЗрдВ рдирд┐рд░реНрдорд╛рдг рджреЛрдиреЛрдВ рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, TaskList рди рдХреЗрд╡рд▓ TaskList рд╣реИрдВрдбрд▓рд░ рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ await рдХреАрд╡рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдпрджрд┐ рд╣реИрдВрдбрд▓рд░ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдХреБрдЫ рднреА рдирд╣реАрдВ рд▓реМрдЯрд╛рдПрдЧрд╛, рдпрд╛ Promise рдЕрд▓рд╛рд╡рд╛ рдХрд┐рд╕реА рднреА рдореВрд▓реНрдп рдХреЛ рд╡рд╛рдкрд╕ рдХрд░реЗрдЧрд╛, рддреЛ TaskList рдШрдЯрдХ рдмрд╕ рд╕рд╛рдорд╛рдиреНрдп рддрд░реАрдХреЗ рд╕реЗ handleAdd рд╡рд┐рдзрд┐ рдХреЛ рдЬрд╛рд░реА рд░рдЦреЗрдЧрд╛ред рд▓реЗрдХрд┐рди рдЕрдЧрд░ рд╣реИрдВрдбрд▓рд░ Promise рд▓реМрдЯрд╛рддрд╛ рд╣реИ (рдпрджрд┐ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдПрдХ async рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд░реВрдк рдореЗрдВ рдШреЛрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ), рддреЛ TaskList рд╣реИрдВрдбрд▓рд░ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрдВрддрдЬрд╛рд░ рдХрд░реЗрдЧрд╛, рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рд╣реА newTaskAdding рдФрд░ newTaskText рдХреЗ рдореВрд▓реНрдпреЛрдВ рдХреЛ рд░реАрд╕реЗрдЯ рдХрд░реЗрдЧрд╛ред

рдЪрд░рдг 1: рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдШрдЯрдХ рдореЗрдВ IndexDB рдЬреЛрдбрд╝реЗрдВ


рдЕрдкрдиреЗ рдХрд╛рдо рдХреЛ рдЖрд╕рд╛рди рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдкрд╣рд▓реЗ рд╣рдо рдПрдХ рд╕рд░рд▓ рдШрдЯрдХ рд▓рд┐рдЦреЗрдВрдЧреЗ рдЬреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддрд░реАрдХреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ:

  • рддреБрдЪреНрдЫ рддреНрд░реБрдЯрд┐ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреЗ рд╕рд╛рде рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдЦреЛрд▓рдиреЗ
  • рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЖрдЗрдЯрдо рдХреЗ рд▓рд┐рдП рдЦреЛрдЬ
  • рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЖрдЗрдЯрдо рдЬреЛрдбрд╝рдирд╛

рдкрд╣рд▓рд╛ рд╕рдмрд╕реЗ "рдЧреИрд░-рддреБрдЪреНрдЫ" рд╣реИ - 5 рдЗрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рдХреЗ рд░реВрдк рдореЗрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдХреЛрдИ рд░реЙрдХреЗрдЯ рд╕рд╛рдЗрдВрд╕ рдирд╣реАрдВ:

OpenDatabasePromise () - рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдЦреЛрд▓реЗрдВ
 function openDatabasePromise( keyPath ) { return new Promise( ( resolve, reject ) => { const dbOpenRequest = window.indexedDB.open( DB_NAME, '1.0.0' ); dbOpenRequest.onblocked = () => { reject( '    ,    , ' + '      .' ); }; dbOpenRequest.onerror = err => { console.log( 'Unable to open indexedDB ' + DB_NAME ); console.log( err ); reject( '   ,       .' + ( err.message ? ' : ' + err.message : '' ) ); }; dbOpenRequest.onupgradeneeded = event => { const db = event.target.result; try { db.deleteObjectStore( OBJECT_STORE_NAME ); } catch ( err ) { console.log( err ); } db.createObjectStore( OBJECT_STORE_NAME, { keyPath } ); }; dbOpenRequest.onsuccess = () => { console.info( 'Successfully open indexedDB connection to ' + DB_NAME ); resolve( dbOpenRequest.result ); }; dbOpenRequest.onerror = reject; } ); } 

getAllPromise / getPromise / putPromise - рдкреНрд░реЛрдкрд░ рдореЗрдВ рд░реИрдкрд░ IndexDb рдХреЙрд▓
 //    ObjectStore,   IDBRequest //     Promise function wrap( methodName ) { return function() { const [ objectStore, ...etc ] = arguments; return new Promise( ( resolve, reject ) => { const request = objectStore[ methodName ]( ...etc ); request.onsuccess = () => resolve( request.result ); request.onerror = reject; } ); }; } const deletePromise = wrap( 'delete' ); const getAllPromise = wrap( 'getAll' ); const getPromise = wrap( 'get' ); const putPromise = wrap( 'put' ); } 

рдпрд╣ рд╕рдм рдПрдХ рд╕рд╛рде рдПрдХ IndexedDbRepository рд╡рд░реНрдЧ рдореЗрдВ рд▓рд╛рдирд╛

IndexedDbRepository - IDBDatabase рдХреЗ рдЖрд╕рдкрд╛рд╕ рдЖрд╡рд░рдг
 const DB_NAME = 'objectStore'; const OBJECT_STORE_NAME = 'objectStore'; /* ... */ export default class IndexedDbRepository { /* ... */ constructor( keyPath ) { this.error = null; this.keyPath = keyPath; //     async //      this.openDatabasePromise = this._openDatabase(); } async _openDatabase( keyPath ) { try { this.dbConnection = await openDatabasePromise( keyPath ); } catch ( error ) { this.error = error; throw error; } } async _tx( txMode, callback ) { await this.openDatabasePromise; // await db connection const transaction = this.dbConnection.transaction( [ OBJECT_STORE_NAME ], txMode ); const objectStore = transaction.objectStore( OBJECT_STORE_NAME ); return await callback( objectStore ); } async findAll() { return this._tx( 'readonly', objectStore => getAllPromise( objectStore ) ); } async findById( key ) { return this._tx( 'readonly', objectStore => getPromise( objectStore, key ) ); } async deleteById( key ) { return this._tx( 'readwrite', objectStore => deletePromise( objectStore, key ) ); } async save( item ) { return this._tx( 'readwrite', objectStore => putPromise( objectStore, item ) ); } } 
( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдЕрдм рдЖрдк IndexDB рдХреЛ рдХреЛрдб рд╕реЗ рдПрдХреНрд╕реЗрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

  const db = new IndexedDbRepository( 'id' ); // ,     await db.save( { id: 42, text: 'Task text' } ); const item = await db.findById( 42 ); const items = await db.findAll(); 

рдЗрд╕ "рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА" рдХреЛ рд╣рдорд╛рд░реЗ рдШрдЯрдХ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВред рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рдирд┐рдпрдореЛрдВ рдХреЗ рдЕрдиреБрд╕рд╛рд░, рд╕рд░реНрд╡рд░ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рдХрдореНрдкреЛрдиреЗрдВрдЯрдбрд┐рдорд╛рдЙрдВрдЯ () рд╡рд┐рдзрд┐ рдореЗрдВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП:

 import IndexedDbRepository from '../common/IndexedDbRepository'; /*...*/ componentDidMount() { this.repository = new IndexedDbRepository( 'id' ); //     this.repository.findAll().then( tasks => this.setState( { tasks } ) ); } 

рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рд░реВрдк рд╕реЗ, ComponentsDidMount componentDidMount() рдлрд╝рдВрдХреНрд╢рди рдХреЛ async рдХреЗ рд░реВрдк рдореЗрдВ рдШреЛрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдлрд┐рд░ async / рдкреНрд░рддреАрдХреНрд╖рд╛ рдирд┐рд░реНрдорд╛рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рддрдм () рдХреЗ рдмрдЬрд╛рдп рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА componentDidMount() "рд╣рдорд╛рд░рд╛" рдлрд╝рдВрдХреНрд╢рди рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд░рд┐рдПрдХреНрдЯ рджреНрд╡рд╛рд░рд╛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдХреМрди рдЬрд╛рдирддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ 17.x рд▓рд╛рдЗрдмреНрд░реЗрд░реА undefined рдмрдЬрд╛рдп Promise рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рдкреНрд░рдпрд╛рд╕ рдХреЗ рдЬрд╡рд╛рдм рдореЗрдВ рдХреИрд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░реЗрдЧреА?

рдЕрдм рдирд┐рд░реНрдорд╛рддрд╛ рдореЗрдВ, рдЗрд╕реЗ рдЦрд╛рд▓реА рд╕рд░рдгреА (рдпрд╛ рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рд╕рд░рдгреА) рдХреЗ рд╕рд╛рде рднрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рд╣рдо рдЗрд╕реЗ рд╢реВрдиреНрдп рд╕реЗ рднрд░ рджреЗрдВрдЧреЗред рдФрд░ рд░реЗрдВрдбрд░ рдХрд░рдиреЗ рдореЗрдВ, рдпрд╣ рдбреЗрдЯрд╛ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдЗрд╕ рдЕрд╢рдХреНрдд рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░реЗрдЧрд╛ред рдЬреЛ рд▓реЛрдЧ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рдЗрд╕реЗ рдЕрд▓рдЧ рдЭрдВрдбреЗ рдореЗрдВ рдбрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╕рдВрд╕реНрдерд╛рдУрдВ рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХреНрдпреЛрдВ рдХрд░рддреЗ рд╣реИрдВ?

  constructor() { super( ...arguments ); this.state = { tasks: null }; /* ... */ } /* ... */ render() { if ( this.state.tasks === null ) return <><Spinner animation="border" aria-hidden="true" as="span" role="status" /><span>  ...</span></>; /* ... */ } 

рдпрд╣ handleAdd рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ / handleDelete :

  constructor() { /* ... */ this.handleAdd = async( newTaskText ) => { await this.repository.save( { id: counter(), text: newTaskText } ); this.setState( { tasks: null } ); this.setState( { tasks: await this.repository.findAll() } ); }; this.handleDelete = async( idToDelete ) => { await this.repository.deleteById( idToDelete ); this.setState( { tasks: null } ); this.setState( { tasks: await this.repository.findAll() } ); }; } 

рджреЛрдиреЛрдВ рд╣реИрдВрдбрд▓рд░ рдореЗрдВ, рд╣рдо рдкрд╣рд▓реЗ рдПрдХ рдЖрдЗрдЯрдо рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдпрд╛ рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреА рдУрд░ рдореБрдбрд╝рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рд╣рдо рд╡рд░реНрддрдорд╛рди рдШрдЯрдХ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕рд╛рдлрд╝ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдлрд┐рд░ рд╕реЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдПрдХ рдирдИ рд╕реВрдЪреА рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рддреЗ рд╣реИрдВред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╕реЗрдЯрд╕реНрдЯреИрдЯ () рдкрд░ рдХреЙрд▓ рдПрдХ рдХреЗ рдмрд╛рдж рдПрдХ рдЬрд╛рдПрдЧреАред рд▓реЗрдХрд┐рди рд╣реИрдВрдбрд▓рд░ рдХреА рдЕрдВрддрд┐рдо рдкрдВрдХреНрддрд┐рдпреЛрдВ рдореЗрдВ рдкреНрд░рддреАрдХреНрд╖рд┐рдд рдХреАрд╡рд░реНрдб рджреВрд╕рд░реА рд╕реЗрдЯрд╕реНрдЯреИрдЯ () рдХреЙрд▓ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рдмрд╛рдж рд╣реА рд╣реЛрдЧрд╛ рдХреНрдпреЛрдВрдХрд┐ рдкреНрд░реЙрдорд┐рд╕ () рд╡рд┐рдзрд┐ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

рдЪрд░рдг 2. рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рд╕реБрдиреЗрдВ


рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдореЗрдВ рдПрдХ рдмрдбрд╝рд╛ рджреЛрд╖ рдпрд╣ рд╣реИ рдХрд┐, рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкреНрд░рддреНрдпреЗрдХ рдШрдЯрдХ рдореЗрдВ рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рд╣реИред рджреВрд╕рд░реЗ, рдпрджрд┐ рдПрдХ рдШрдЯрдХ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдмрджрд▓рддрд╛ рд╣реИ, рддреЛ рджреВрд╕рд░реЗ рдШрдЯрдХ рдХреЛ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рддрдм рддрдХ рдкрддрд╛ рдирд╣реАрдВ рдЪрд▓рддрд╛ рд╣реИ рдЬрдм рддрдХ рдХрд┐ рдпрд╣ рдХрд┐рд╕реА рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рд░рд╛рдЬреНрдп рдХреЛ рдлрд┐рд░ рд╕реЗ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред

рдЗрд╕рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдирдП рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рд▓рд┐рд╕реНрдЯрдирд░ рдШрдЯрдХ рдХреЛ рдкреЗрд╢ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЗрд╕реЗ рджреЛ рдХрд╛рдо рдХрд░рдиреЗ рджреЗрдВрдЧреЗред рдпрд╣ рдШрдЯрдХ, рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХреА рд╕рджрд╕реНрдпрддрд╛ рд▓реЗ рд╕рдХреЗрдЧрд╛ред рджреВрд╕рд░реЗ, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд▓рд┐рд╕реНрдЯрдирд░ рдЙрд╕ рдШрдЯрдХ рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░реЗрдЧрд╛ рдЬрд┐рд╕рдиреЗ рдЗрд╕реЗ рдЗрди рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рдмрдирд╛рдпрд╛ рдерд╛ред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, IndexedDbRepository рдореЗрдВ рд╣реИрдВрдбрд▓рд░реНрд╕ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝рдирд╛:

 export default class IndexedDbRepository { /*...*/ constructor( keyPath ) { /*...*/ this.listeners = new Set(); this.stamp = 0; /*...*/ } /*...*/ addListener( listener ) { this.listeners.add( listener ); } onChange() { this.stamp++; this.listeners.forEach( listener => listener( this.stamp ) ); } removeListener( listener ) { this.listeners.delete( listener ); } } 

( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рд╣рдо рд╣реИрдВрдбрд▓рд░ рдХреЛ рдПрдХ рд╕реНрдЯрд╛рдВрдк рдкрд╛рд╕ рдХрд░реЗрдВрдЧреЗ, рдЬреЛ рд╣рд░ рдХреЙрд▓ рдХреЗ рд╕рд╛рде onChange () рдореЗрдВ рдмрджрд▓ рдЬрд╛рдПрдЧрд╛ред рдФрд░ рд╣рдо _tx рд╡рд┐рдзрд┐ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рд░реАрдб рд░рд╛рдЗрдЯ рдореЛрдб рдХреЗ рд╕рд╛рде рд▓реЗрдирджреЗрди рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдХреЙрд▓ рдХреЗ рд▓рд┐рдП onChange onChange() рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдП:

  async _tx( txMode, callback ) { await this.openDatabasePromise; // await db connection try { const transaction = this.dbConnection.transaction( [ OBJECT_STORE_NAME ], txMode ); const objectStore = transaction.objectStore( OBJECT_STORE_NAME ); return await callback( objectStore ); } finally { if ( txMode === 'readwrite' ) this.onChange(); // notify listeners } } 

( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдЕрдЧрд░ рд╣рдо рдЕрднреА рднреА then() / catch() рдХрд╛ рдЙрдкрдпреЛрдЧ рдкреНрд░реЙрдорд┐рд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдпрд╛ рддреЛ onChange() рдХреЛ рдХреЙрд▓ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдпрд╛ рдкреНрд░реЛрдорд┐рд╕ () рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖ рдкреЙрд▓реАрдлрд╝рд┐рд▓реНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдЬреЛ final() рд╕рдорд░реНрдерди рдХрд░рддреЗ рд╣реИрдВред рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, async / рдкреНрд░рддреАрдХреНрд╖рд╛ рдЖрдкрдХреЛ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдФрд░ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдХреЛрдб рдХреЗ рдпрд╣ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред

рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рд▓рд┐рд╕реНрдЯрд░реНрди рдШрдЯрдХ рд╕реНрд╡рдпрдВ рдПрдХ рдИрд╡реЗрдВрдЯ рд╢реНрд░реЛрддрд╛ рдХреЛ рдХрдВрдкреЛрдиреЗрдВрдЯрдбрд┐рдорд╛рдЙрдВрдЯ рдФрд░ рдХрдВрдкреЛрдиреЗрдВрдЯрд╡рд┐рд▓рд╛рдЙрдиреНрдорд╛рдЙрдВрдЯ рддрд░реАрдХреЛрдВ рд╕реЗ рдЬреЛрдбрд╝рддрд╛ рд╣реИ:

рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд▓рд┐рд╕реНрдЯрдирд░ рдХреЛрдб
 import IndexedDbRepository from './IndexedDbRepository'; import { PureComponent } from 'react'; export default class RepositoryListener extends PureComponent { constructor() { super( ...arguments ); this.prevRepository = null; this.repositoryListener = repositoryStamp => this.props.onChange( repositoryStamp ); } componentDidMount() { this.subscribe(); } componentDidUpdate() { this.subscribe(); } componentWillUnmount() { this.unsubscribe(); } subscribe() { const { repository } = this.props; if ( repository instanceof IndexedDbRepository && this.prevRepository !== repository ) { if ( this.prevRepository !== null ) { this.prevRepository.removeListener( this.repositoryListener ); } this.prevRepository = repository; repository.addListener( this.repositoryListener ); } } unsubscribe( ) { if ( this.prevRepository !== null ) { this.prevRepository.removeListener( this.repositoryListener ); this.prevRepository = null; } } render() { return this.props.children || null; } } 
( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдЕрдм, рд╣рдо рдЕрдкрдиреЗ рдореБрдЦреНрдп рдШрдЯрдХ рдореЗрдВ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкрд░рд┐рд╡рд░реНрддрди рдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВрдЧреЗ, рдФрд░, DRY рд╕рд┐рджреНрдзрд╛рдВрдд рджреНрд╡рд╛рд░рд╛ рдирд┐рд░реНрджреЗрд╢рд┐рдд, рд╣рдо handleAdd / handleDelete рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдХреЛрдб рдХреЛ рд╣рдЯрд╛ рджреЗрдВрдЧреЗ:

  constructor() { super( ...arguments ); this.state = { tasks: null }; this.handleAdd = async( newTaskText ) => { await this.repository.save( { id: counter(), text: newTaskText } ); }; this.handleDelete = async( idToDelete ) => { await this.repository.deleteById( idToDelete ); }; this.handleRepositoryChanged = async() => { this.setState( { tasks: null } ); this.setState( { tasks: await this.repository.findAll() } ); }; } componentDidMount() { this.repository = new IndexedDbRepository( 'id' ); this.handleRepositoryChanged(); // initial load } 

( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдФрд░ рд╣рдо рдХрдиреЗрдХреНрдЯреЗрдб рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд▓рд┐рд╕реНрдЯрд░реНрди рд╕реЗ рд╣реИрдВрдбреНрд░рд┐рдкреЗрдЯрд░реАрдЪрд╛рд░реНрдЬ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдХреЙрд▓ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ:

  render() { /* ... */ return <RepositoryListener onChange={this.handleRepoChanged} repository={this.repository}> <TaskList onAdd={this.handleAdd} onDelete={this.handleDelete} tasks={this.state.tasks} /> </RepositoryListener>; } 

( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдЪрд░рдг 3. рдбреЗрдЯрд╛ рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдФрд░ рдЙрд╕рдХреЗ рдЕрджреНрдпрддрди рдХреЛ рдПрдХ рдЕрд▓рдЧ рдШрдЯрдХ рдореЗрдВ рдирд┐рдХрд╛рд▓реЗрдВ


рд╣рдордиреЗ рдПрдХ рдШрдЯрдХ рд▓рд┐рдЦрд╛ рд╣реИ рдЬреЛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдбреЗрдЯрд╛ рдмрджрд▓ рд╕рдХрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЖрдк 100+ рдШрдЯрдХреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдмрдбрд╝реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдШрдЯрдХ рдЬреЛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдЙрд╕реЗ рдордЬрдмреВрд░ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛:

  • рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рднрдВрдбрд╛рд░ рдПрдХрд▓ рдмрд┐рдВрджреБ рд╕реЗ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рд╣реИ
  • ComponentsDidMount componentDidMount() рд╡рд┐рдзрд┐ рдореЗрдВ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдбреЗрдЯрд╛ рд▓реЛрдбрд┐рдВрдЧ рдкреНрд░рджрд╛рди рдХрд░реЗрдВ
  • RepositoryListener рдШрдЯрдХ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ, рдЬреЛ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рдкреБрдирдГ рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИрдВрдбрд▓рд░ рдХреЙрд▓ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ

рдХреНрдпрд╛ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдХреНрд░рд┐рдпрд╛рдПрдВ рд╣реИрдВ? рдРрд╕рд╛ рдирд╣реАрдВ рд▓рдЧрддрд╛ред рдФрд░ рдЕрдЧрд░ рдХреБрдЫ рднреВрд▓ рдЧрдпрд╛ рд╣реИ? рдХреЙрдкреА рдкреЗрд╕реНрдЯ рдХреЗ рд╕рд╛рде рдЦреЛ рдЬрд╛рдУ?

рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдХрд┐ рд╣рдо рдПрдХ рдмрд╛рд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреА рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдирд┐рдпрдо рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рдФрд░ рдХреБрдЫ рдЬрд╛рджреБрдИ рдЗрди рддрд░реАрдХреЛрдВ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИ, рд╣рдореЗрдВ рдбреЗрдЯрд╛ рджреЗрддрд╛ рд╣реИ, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдПрдВ рдмрджрд▓рддрд╛ рд╣реИ, рдФрд░ рдвреЗрд░ рдХреЗ рд▓рд┐рдП рдпрд╣ рдЗрд╕реЗ рдХрдиреЗрдХреНрдЯ рднреА рдХрд░ рд╕рдХрддрд╛ рд╣реИ рднрдВрдбрд╛рд░ред

 this.doFindAllTasks = ( repo ) => repo.findAll(); /*...*/ <DataProvider doCalc={ this.doFindAllTasks }> {(data) => <span>...   -,   data...</span>} </DataProvider> 

рдЗрд╕ рдШрдЯрдХ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рд╕рдордп рд╣реИ рдХрд┐ doFindAllTasks () рд╡рд╛рджрд╛ рд╣реИред рдЕрдкрдиреЗ рдХрд╛рдо рдХреЛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдЕрд▓рдЧ рдШрдЯрдХ рдмрдирд╛рдПрдВрдЧреЗ, рдЬреЛ рдПрдХ рдкрд░рд┐рдХрд▓рд┐рдд рдореВрд▓реНрдп рдХреЗ рд╕рд╛рде рд╡рдВрд╢ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдФрд░ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд╛рджреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣рд╛ рд╣реИ:

PromiseComponent рдХреЛрдб
 import { PureComponent } from 'react'; export default class PromiseComponent extends PureComponent { constructor() { super( ...arguments ); this.state = { error: null, value: null, }; this.prevPromise = null; } componentDidMount() { this.subscribe(); } componentDidUpdate( ) { this.subscribe(); } componentWillUnmount() { this.unsubscribe(); } subscribe() { const { cleanOnPromiseChange, promise } = this.props; if ( promise instanceof Promise && this.prevPromise !== promise ) { if ( cleanOnPromiseChange ) this.setState( { error: null, value: null } ); this.prevPromise = promise; promise.then( value => { if ( this.prevPromise === promise ) { this.setState( { error: null, value } ); } } ) .catch( error => { if ( this.prevPromise === promise ) { this.setState( { error, value: null } ); } } ); } } unsubscribe( ) { if ( this.prevPromise !== null ) { this.prevPromise = null; } } render() { const { children, fallback } = this.props; const { error, value } = this.state; if ( error !== null ) { throw error; } if ( value === undefined || value === null ) { return fallback || null; } return children( value ); } } 

( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдЗрд╕рдХреЗ рддрд░реНрдХ рдФрд░ рдЖрдВрддрд░рд┐рдХ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдпрд╣ рдШрдЯрдХ рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рд▓рд┐рд╕реНрдЯрдирд░ рдХреЗ рд╕рдорд╛рди рд╣реИред рдХреНрдпреЛрдВрдХрд┐ рджреЛрдиреЛрдВ рдПрдХ рдФрд░ рджреВрд╕рд░реЗ рдХреЛ "рд╕рд╛рдЗрди" рдХрд░рдирд╛, рдШрдЯрдирд╛рдУрдВ рдХреЛ "рд╕реБрдирдирд╛" рдФрд░ рдХрд┐рд╕реА рддрд░рд╣ рдЙрдиреНрд╣реЗрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдФрд░ рдпрд╣ рднреА рдзреНрдпрд╛рди рд░рдЦреЗрдВ рдХрд┐ рдЬрд┐рдирдХреА рдШрдЯрдирд╛рдУрдВ рдХреЛ рдЖрдкрдХреЛ рд╕реБрдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рд╡реЗ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдмрд╣реБрдд рд╣реА рдЬрд╛рджреБрдИ рдШрдЯрдХ DataProvider рдЕрдм рддрдХ рдмрд╣реБрдд рд╕рд░рд▓ рджрд┐рдЦрддрд╛ рд╣реИ:

 import repository from './RepositoryHolder'; /*...*/ export default class DataProvider extends PureComponent { constructor() { super( ...arguments ); this.handleRepoChanged = () => this.forceUpdate(); } render() { return <RepositoryListener onChange={this.handleRepoChanged} repository={repository}> <PromiseComponent promise={this.props.doCalc( repository )}> {data => this.props.children( data )} </PromiseComponent> </RepositoryListener>; } } 

( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдордиреЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА (рдФрд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╕рд┐рдВрдЧреНрд▓реЛрдирдЯрди рд░рд┐рдкреЛрдЬрд┐рдЯрд░реАрд╣реЛрд▓реНрдбрд░, рдЬреЛ рдЕрдм рдЖрдпрд╛рдд рдореЗрдВ рд╣реИ) рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛, рдЬрд┐рд╕реЗ doCalc рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдпрд╣ рд╣рдореЗрдВ рдХрд╛рд░реНрдп рдбреЗрдЯрд╛ рдХреЛ рдЗрд╕ .props.children рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛, рдФрд░ рдЗрд╕рд▓рд┐рдП, рдХрд╛рд░реНрдпреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рддреИрдпрд╛рд░ рдХрд░реЗрдВред рд╕рд┐рдВрдЧрд▓реЗрдВрдЯрди рднреА рд╕рд░рд▓ рджрд┐рдЦрддрд╛ рд╣реИ:

 const repository = new IndexedDbRepository( 'id' ); export default repository; 

рдЕрдм DataProvider рдХреЙрд▓ рдХреЗ рд╕рд╛рде рдореБрдЦреНрдп рдХреЙрд▓ рд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЙрд▓ рдХреЛ рдмрджрд▓реЗрдВ:

 import repository from './RepositoryHolder'; /* ... */ export default class Step3 extends PureComponent { constructor() { super( ...arguments ); this.doFindAllTasks = repository => repository.findAll(); /* ... */ } render() { return <DataProvider doCalc={this.doFindAllTasks} fallback={<><Spinner animation="border" aria-hidden="true" as="span" role="status" /><span>  ...</span></>}> { tasks => <TaskList onAdd={this.handleAdd} onDelete={this.handleDelete} tasks={tasks} /> } </DataProvider>; } } 

( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдпрд╣ рд░реБрдХ рд╕рдХрддрд╛ рдерд╛ред рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдирд┐рдХрд▓рд╛: рд╣рдо рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐рдпрдо рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдПрдХ рдЕрд▓рдЧ рдШрдЯрдХ рдЗрд╕ рдбреЗрдЯрд╛ рдХреА рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкреНрд░рд╛рдкреНрддрд┐ рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХрд░рддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рд╕рд╛рде рдЕрджреНрдпрддрди рднреА рдХрд░рддрд╛ рд╣реИред рд╡рд╕реНрддреБрддрдГ рдЫреЛрдЯреА-рдЫреЛрдЯреА рдмрд╛рддреЗрдВ рдереАрдВ:

  • рдкреНрд░рддреНрдпреЗрдХ рдбреЗрдЯрд╛ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП, рдХреЛрдб рдореЗрдВ рдХрд╣реАрдВ (рд▓реЗрдХрд┐рди render() рд╡рд┐рдзрд┐ рдореЗрдВ рдирд╣реАрдВ render() рдЖрдкрдХреЛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреЗ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдбреЗрдЯрд╛рдкреНрд░реЛрд╡рд╛рдЗрдбрд░ рдХреЛ рдкрд╛рд╕ рдХрд░реЗрдВ
  • DataProvider рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреА рднрд╛рд╡рдирд╛ рдореЗрдВ рдорд╣рд╛рди рдФрд░ рдХрд╛рдлреА рд╣реИ, рд▓реЗрдХрд┐рди JSX рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ рдмрд╣реБрдд рдмрджрд╕реВрд░рдд рд╣реИред рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдХрдИ рдШрдЯрдХ рд╣реИрдВ, рддреЛ рд╡рд┐рднрд┐рдиреНрди DataProviders рдХреЗ рдШреЛрдВрд╕рд▓реЗ рдХреЗ рд╢рд┐рдХрд╛рд░ рдХреЗ рджреЛ рдпрд╛ рддреАрди рд╕реНрддрд░ рдЖрдкрдХреЛ рдмрд╣реБрдд рднреНрд░рдорд┐рдд рдХрд░реЗрдВрдЧреЗред
  • рдпрд╣ рджреБрдЦрдж рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдПрдХ рдШрдЯрдХ (рдбреЗрдЯрд╛рдкреНрд░реЛрдЗрдбрд░) рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЙрдирдХрд╛ рдкрд░рд┐рд╡рд░реНрддрди рджреВрд╕рд░реЗ (рдореБрдЦреНрдп рдШрдЯрдХ) рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдореИрдВ рдЙрд╕реА рддрдВрддреНрд░ рдХреЗ рд╕рд╛рде рдЗрд╕рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ред

рдЪрд░рдг 4. рдХрдиреЗрдХреНрдЯ ()


рд╢реАрд░реНрд╖рдХ рдХреЗ рд╢реАрд░реНрд╖рдХ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рд░рд┐рдбреНрдпреВрдХреНрд╕ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рдореИрдВ рдмрд╛рдХреА рдХреЗ рд▓рд┐рдП рд╕рдВрдХреЗрдд рджреЗрдЧрд╛: рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐, рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде рдмрдЪреНрдЪреЛрдВ () рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рдбреЗрдЯрд╛рдкреНрд░реЛрд╡рд╛рдЗрдбрд░ рд╕реЗрд╡рд╛ рдШрдЯрдХ рдирд┐рдпрдореЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╣рдорд╛рд░реЗ рдШрдЯрдХ рдХреЗ рдЧреБрдгреЛрдВ рдХреЛ рднрд░ рджреЗрдЧрд╛ред рдФрд░ рдЕрдЧрд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдХреБрдЫ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ, рддреЛ рдпрд╣ рдмрд╕ рдорд╛рдирдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рддрдВрддреНрд░ рдХреЗ рд╕рд╛рде рдЧреБрдгреЛрдВ рдХреЛ рдмрджрд▓ рджреЗрдЧрд╛ред

рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рд╣рд╛рдпрд░ рдСрд░реНрдбрд░ рдХрдВрдкреЛрдиреЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рдХреБрдЫ рднреА рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд╣реИ, рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдПрдХ рдШрдЯрдХ рд╡рд░реНрдЧ рдХреЛ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ рдФрд░ рдПрдХ рдФрд░, рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдШрдЯрдХ рджреЗрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдорд╛рд░рд╛ рдХрд╛рд░реНрдп рдЬреЛ рд╣рдо рд▓рд┐рдЦрддреЗ рд╣реИрдВ рд╡рд╣ рд╣реЛрдЧрд╛:

  • рдПрдХ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдШрдЯрдХ рд╡рд░реНрдЧ рд▓реЗрдВ рдЬрд╣рд╛рдВ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рдирд╛ рд╣реИ
  • рдирд┐рдпрдореЛрдВ рдХрд╛ рдПрдХ рд╕реЗрдЯ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░реЗрдВ, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдбреЗрдЯрд╛ рдХреИрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ, рдФрд░ рдЗрд╕реЗ рдХрд┐рд╕ рдЧреБрдгреЛрдВ рдореЗрдВ рдбрд╛рд▓реЗрдВ
  • рдЗрд╕рдХреЗ рдЙрдкрдпреЛрдЧ рдореЗрдВ, рдпрд╣ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рд░рд┐рдбрдХреНрд╕ рд╕реЗ рдХрдиреЗрдХреНрдЯ () рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рдорд╛рди рд╣реЛрдЧрд╛ред

рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдХреЙрд▓ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛:

 const mapRepoToProps = repository => ( { tasks: repository.findAll(), } ); const mapRepoToActions = repository => ( { doAdd: ( newTaskText ) => repository.save( { id: counter(), text: newTaskText } ), doDelete: ( idToDelete ) => repository.deleteById( idToDelete ), } ); const Step4Connected = connect( mapRepoToProps, mapRepoToActions )( Step4 ); 

рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐рдпрд╛рдБ Step4 рдШрдЯрдХ рдХреЗ рдЧреБрдг рдирд╛рдо рдФрд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рд▓реЛрдб рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдорд╛рдиреЛрдВ рдХреЗ рдмреАрдЪ рдореИрдкрд┐рдВрдЧ рдХреЛ Step4 рд╣реИрдВред рдЗрд╕рдХреЗ рдмрд╛рдж рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдореИрдкрд┐рдВрдЧ рдЖрддреА рд╣реИ: рдпрджрд┐ Step4 рдШрдЯрдХ рдХреЗ рднреАрддрд░ this.props.doDelete(...) this.props.doAdd(...) рдпрд╛ this.props.doDelete(...) рдХреЛ рдХреЙрд▓ Step4 рд╣реИрдВ рддреЛ рдХреНрдпрд╛ рд╣реЛрдЧрд╛ред рдФрд░ рдЕрдВрддрд┐рдо рдкрдВрдХреНрддрд┐ рд╕рдм рдХреБрдЫ рдПрдХ рд╕рд╛рде рд▓рд╛рддреА рд╣реИ рдФрд░ рдХрдиреЗрдХреНрдЯ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рддреА рд╣реИред рдкрд░рд┐рдгрд╛рдо рдПрдХ рдирдпрд╛ рдШрдЯрдХ рд╣реИ (рдпрд╣реА рд╡рдЬрд╣ рд╣реИ рдХрд┐ рдЗрд╕ рддрдХрдиреАрдХ рдХреЛ рд╣рд╛рдпрд░ рдСрд░реНрдбрд░ рдХрдВрдкреЛрдиреЗрдВрдЯ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ)ред рдФрд░ рд╣рдо рдЕрдм рдореВрд▓ Step4 рдШрдЯрдХ рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдирд┐рд░реНрдпрд╛рдд рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рдЪрд╛рд░реЛрдВ рдУрд░ рдЖрд╡рд░рдг:

 /*...*/ class Step4 extends PureComponent { /*...*/ } /*...*/ const Step4Connected = connect( /*...*/ )( Step4 ); export default Step4Connected; 

рдФрд░ рдЯрд╛рд╕реНрдХрд▓рд┐рд╕реНрдЯ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдШрдЯрдХ рдЕрдм рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЖрд╡рд░рдг рдХреА рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

 class Step4 extends PureComponent { render() { return this.props.tasks === undefined || this.props.tasks === null ? <><Spinner animation="border" aria-hidden="true" as="span" role="status" /><span>  ...</span></> : <TaskList onAdd={this.props.doAdd} onDelete={this.props.doDelete} tasks={this.props.tasks} />; } } 

( рдЬреАрдереВрдм рд╕реЛрд░реНрд╕ рдХреЛрдб )

рдФрд░ рд╡рд╣ рдпрд╣ рд╣реИред рдХреЛрдИ рдирд┐рд░реНрдорд╛рддрд╛, рдХреЛрдИ рдЕрддрд┐рд░рд┐рдХреНрдд рд╣реИрдВрдбрд▓рд░ рдирд╣реАрдВ - рдШрдЯрдХ рдХреЗ рдкреНрд░реЙрдкрд░ рдореЗрдВ рдХрдиреЗрдХреНрдЯ () рдлрд╝рдВрдХреНрд╢рди рджреНрд╡рд╛рд░рд╛ рд╕рдм рдХреБрдЫ рд░рдЦрд╛ рдЧрдпрд╛ рд╣реИред

рдпрд╣ рджреЗрдЦрдирд╛ рдмрд╛рдХреА рд╣реИ рдХрд┐ рдХрдиреЗрдХреНрдЯ () рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреИрд╕реЗ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред

рдХрдиреЗрдХреНрдЯ () рдХреЛрдб
 import repository from './RepositoryHolder'; /* ... */ class Connected extends PureComponent { constructor() { super( ...arguments ); this.handleRepoChanged = () => this.forceUpdate(); } render() { const { childClass, childProps, mapRepoToProps, mapRepoToActions } = this.props; const promises = mapRepoToProps( repository, childProps ); const actions = mapRepoToActions( repository, childProps ); return <RepositoryListener onChange={this.handleRepoChanged} repository={repository}> <PromisesComponent promises={promises}> { values => React.createElement( childClass, { ...childProps, ...values, ...actions, } )} </PromisesComponent> </RepositoryListener>; } } export default function connect( mapRepoToProps, mapRepoToActions ) { return childClass => props => <Connected childClass={childClass} childProps={props} mapRepoToActions={mapRepoToActions} mapRepoToProps={mapRepoToProps} />; } 
( рдЬреАрдереБрдм рд╕реНрд░реЛрдд рдХреЛрдб )

рдХреЛрдб рднреА рдмрд╣реБрдд рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд▓рдЧрддрд╛ рд╣реИ ... рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрджрд┐ рдЖрдк рдбрд╛рдЗрд╡рд┐рдВрдЧ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╕рд╡рд╛рд▓ рдЙрдареЗрдВрдЧреЗред рдЖрдкрдХреЛ рдЕрдВрдд рд╕реЗ рдкрдврд╝рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИред рдпрд╣ рд╡рд╣рд╛рдБ рд╣реИ рдХрд┐ connect() рдлрд╝рдВрдХреНрд╢рди рдкрд░рд┐рднрд╛рд╖рд┐рдд рд╣реИред рдпрд╣ рджреЛ рдкреИрд░рд╛рдореАрдЯрд░ рд▓реЗрддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рджреЗрддрд╛ рд╣реИ рдЬреЛ рд╡рд╛рдкрд╕ рд▓реМрдЯрддрд╛ рд╣реИ ... рдлрд┐рд░ рд╕реЗ рдПрдХ рдлрд╝рдВрдХреНрд╢рди? рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдирд╣реАрдВред props => <Connected... рдХрд╛ рдЕрдВрддрд┐рдо рдирд┐рд░реНрдорд╛рдг props => <Connected... рди рдХреЗрд╡рд▓ рдПрдХ рдлрд╝рдВрдХреНрд╢рди, рдмрд▓реНрдХрд┐ рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдШрдЯрдХ рджреЗрддрд╛ рд╣реИ ред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЬрдм рд╣рдо рдПрдХ рдкреЗрдбрд╝ рдореЗрдВ рдХрдиреЗрдХреНрдЯреЗрдбрд╕реНрдЯреЗрдк 4 рдХреЛ рдПрдореНрдмреЗрдб рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЗрд╕рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛрдЧрд╛:

  • рдореВрд▓ -> рдЕрдирд╛рдо рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдШрдЯрдХ -> рдХрдиреЗрдХреНрдЯ -> рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рд▓рд┐рд╕реНрдЯрдирд░ -> рдкреНрд░реЛрдорд┐рд╕рдХрдВрдкреЛрдиреЗрдВрдЯ -> рд╕реНрдЯреЗрдк 4

4 рдЗрдВрдЯрд░рдореАрдбрд┐рдПрдЯ рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдХрдИ, рд▓реЗрдХрд┐рди рдкреНрд░рддреНрдпреЗрдХ рдЕрдкрдирд╛ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред рдПрдХ рдЕрдирд╛рдо рдШрдЯрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рджрд┐рдП рдЧрдП рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рд▓реЗ рдЬрд╛рддрд╛ рд╣реИ connect(), рдиреЗрд╕реНрдЯреЗрдб рдШрдЯрдХ рдХрд╛ рд╡рд░реНрдЧ, рдЧреБрдг рдЬреЛ рдШрдЯрдХ рдХреЛ рддрдм рд╣реА рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ рдЬрдм (рдкреНрд░реЙрдореНрдкреНрд╕) рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдШрдЯрдХ рдХреЛ рдкрд╛рд╕ рдХрд░ рджреЗрддрд╛ рд╣реИ Connectред рдШрдЯрдХ Connectрдкрд╛рд░рд┐рдд рдорд╛рдкрджрдВрдбреЛрдВ Promise(рдкрдВрдХреНрддрд┐ рдХреБрдВрдЬрд┐рдпреЛрдВ рдФрд░ рд╡рд╛рджрд╛ рдореВрд▓реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рд╡рд╕реНрддреБ) рд╕реЗ рдПрдХ рд╕реЗрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ ред PromisesComponentрдореВрд▓реНрдпреЛрдВ рдХреА рдЧрдгрдирд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдЙрдиреНрд╣реЗрдВ рдХрдиреЗрдХреНрдЯ рдШрдЯрдХ рдореЗрдВ рд╡рд╛рдкрд╕ рднреЗрдЬ рд░рд╣рд╛ рд╣реИ, рдЬреЛ рдореВрд▓ рд╣рд╕реНрддрд╛рдВрддрд░рд┐рдд рдЧреБрдгреЛрдВ (рдкреНрд░реЙрдкреНрд╕), рдкрд░рд┐рдХрд▓рд┐рдд рдЧреБрдгреЛрдВ (рдореВрд▓реНрдпреЛрдВ) рдФрд░ рдЧреБрдг-рдХреНрд░рд┐рдпрд╛рдУрдВ (рдХреНрд░рд┐рдпрд╛рдУрдВ) рдХреЗ рд╕рд╛рде рдорд┐рд▓рдХрд░ рдЙрдиреНрд╣реЗрдВ рдШрдЯрдХ Step4(рдПрдХ рдХреЙрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ React.createElement(...)) рддрдХ рдкрд╣реБрдВрдЪрд╛рддрд╛ рд╣реИ ред рдЦреИрд░, рдШрдЯрдХRepositoryListenerрдШрдЯрдХ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рддрд╛ рд╣реИ, рдЕрдЧрд░ рдХреБрдЫ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ рддреЛ рдкреНрд░реЙрдорд┐рд╕ рдХреЛ рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░рддрд╛ рд╣реИред

рдирддреАрдЬрддрди, рдпрджрд┐ рдХреЛрдИ рднреА рдШрдЯрдХ рдЗрдВрдбреЗрдХреНрд╕рдбрдм рд╕реЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдЙрд╕рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реЛрдЧрд╛ рдХрд┐ рд╡рд╣ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдЬреЛрдбрд╝реЗ, connect()рд╕рдВрдкрддреНрддрд┐рдпреЛрдВ рдФрд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдЧреБрдг рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдмреАрдЪ рдореИрдкрд┐рдВрдЧ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВ, рдФрд░ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдЕрддрд┐рд░рд┐рдХреНрдд рд╕рд┐рд░рджрд░реНрдж рдХреЗ рдХрд░реЗрдВред

рдЪрд░рдг 5. @ vlsergey / react-indexdb-repo


рдЕрдВрдд рдореЗрдВ, рд╣рдо рдпрд╣ рд╕рдм рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рд░реВрдк рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдЕрдиреНрдп рдбреЗрд╡рд▓рдкрд░реНрд╕ рдЗрд╕реЗ рдЕрдкрдиреА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХреЗрдВред рдЗрд╕ рдХрджрдо рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдерд╛:



рдХрд┐рд╕реА рдирд┐рд╖реНрдХрд░реНрд╖ рдХреЗ рдмрдЬрд╛рдп: рдХреНрдпрд╛ рдмрдЪрд╛ рд╣реИ


рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдФрджреНрдпреЛрдЧрд┐рдХ рд╕рдорд╛рдзрд╛рдиреЛрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд╣реИред рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА, рд╕реАрдорд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдордд рднреВрд▓рдирд╛:

  • рд╣рдореЗрд╢рд╛ рдмрджрд▓рддреЗ рдЧреБрдгреЛрдВ рд╕реЗ рдирдП рд╡рд╛рджреЗ рдирд╣реАрдВ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред рдпрд╣рд╛рдВ рдЖрдкрдХреЛ рд╕рдВрд╕реНрдорд░рдг рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдбреЗрдЯрд╛рдмреЗрд╕ рдкрд░рд┐рд╡рд░реНрддрди рдзреНрд╡рдЬ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦреЗрдВред рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдБ IndexedDbRepository рд╕реЗ рд╕реНрдЯрд╛рдореНрдк рдХрд╛рдо рдореЗрдВ рдЖрддрд╛ рд╣реИ (рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХреБрдЫ рдХреЗ рд▓рд┐рдП рдпрд╣ рдХреЛрдб рдмреЗрдорд╛рдиреА рд▓рдЧ рд░рд╣рд╛ рдерд╛)ред
  • рдЖрдпрд╛рдд рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рднрдВрдбрд╛рд░ рдХреЛ рдЬреЛрдбрд╝рдирд╛, рднрд▓реЗ рд╣реА рдПрдХ рд╣реА рд╕реНрдерд╛рди рдкрд░ рд╣реЛ, рдЧрд▓рдд рд╣реИред рд╕рдВрджрд░реНрднреЛрдВ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреА рдУрд░ рджреЗрдЦрдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред
  • , IndexedDB .
  • : . . IndexDB ┬л┬╗ , тАФ .
  • , IndexDB Redux Storage. IndexDB , .



Online-

Source: https://habr.com/ru/post/hi472246/


All Articles