⬆️ ⬇️

Replace and Conquer - the SOLID approach to developing reusable components on the web

When developing any, even a simple web application, it becomes necessary to reuse code. In different parts of the site, sooner or later, similar sections of markup and logic are found that I don’t want to duplicate at all. However, in solving this problem it is very easy to step on a rake and make everything very bad.



This article is largely inspired by the report of Pavel Silin on RIT 2017 , but there is a lot of my own experience and reflections here. Examples will be on React + TypeScript, however the approach is not tied to any technology.







How not to do



When you meet with the situation of duplication of code, it becomes natural to put this code into a separate component and use it wherever necessary. Take for example the modal window. It would seem that it could be easier - they took and did:



ShowModalWindow(header: string, content: JSX.Element): Promise<ModalWindowResult>;


, , . , - "", "". , , :



ShowModalWindow(header: string, content: JSX.Element, buttons?: string[]): Promise<ModalWindowResult>;


, . β€” , . , β€” ? , :



ShowModalWindow(header: string, content: JSX.Element, buttons?: string[], showOverlay?: boolean): Promise<ModalWindowResult>;


, . "" , , , - , - …



β€” "", - . , , , . , - , . , .



, β€” - props, jquery- , , ASP.NET Razor , , scss mixin .. .





β€” , 2000- SOLID. , SOLID - , react β€” react-.



, . , " ". S, . :



  1. S (single responsibility) β€” , ;
  2. O (open-closed) β€” , , ;
  3. L (Liskov substitution) β€” , ;
  4. I (interface segregation) β€” "" ;
  5. D (dependency inversion) β€” , , .


. ( ) , LEGO. . β€” , . - , , (, ). , , , , . , , , - .



, , , . , - . β€” ( ).



. :





, , . . , . . , :



  1. β€” - ;
  2. β€” div ;
  3. β€” ;
  4. β€” ;
  5. β€” ( );
  6. ();
  7. β€” ;
  8. β€” ;
  9. β€” , .


- :



     <ModalBackdrop onClick={() => this.setState({ dialogOpen: false })} />
         <ModalDialog open={this.state.dialogOpen} >
             <ModalDialogBox>
                 <ModalDialogHeaderBox>
                     <ModalDialogCloseButton onClick={() => this.setState({ dialogOpen: false })} />
                     <ModalDialogHeader>Dialog header</ModalDialogHeader>
                 </ModalDialogHeaderBox>
                 <ModalDialogContent>Some content</ModalDialogContent>
                 <ModalDialogButtonPanel>
                     <Button onClick={() => this.setState({ dialogOpen: false })} key="cancel">
                         {resources.Navigator_ButtonClose}
                     </Button>
                     <Button disabled={!this.state.directoryDialogSelectedValue}
                         onClick={this.onDirectoryDialogSelectButtonClick} key="ok">
                         {resources.Navigator_ButtonSelect}
                     </Button>
                 </ModalDialogButtonPanel>
             </ModalDialogBox>
         </ModalDialog>
     </ModalBackdrop>


, , div css-. , ModalDialogContent :



    // JS
    export const ModalDialogContent = (props: IModalDialogContentProps) => {
        return (
            <div className="modal-dialog-content-helper">{props.children}</div>
        );
    }
    // CSS
    .modal-dialog-content-helper {
        padding: 0 15px 20px 15px;
    }


, ModalDialogContent div, . , ModalBackdrop. SOLID: (S, I), (D), (L), - (O).



, , , . , ModalDialogBox . , . , . , , β€” , . , . , , .



, -, . , β€” , . , :



   <CommonModalDialog header="Header text" 
          isOpen={this.state.open} onClose={this.onClose}>
       Modal content
   </CommonModalDialog>


, , . - , - , . ( , ), .





SOLID, . , , . :



  1. . . , , , , , . , β€” ( β€” ).
  2. . , , 9 . , . .. , .


.





, , , … , . ? , . β€” ( ), ( ), ( ). , - . , , . , , , ( SOLID) - .



, . , , , . , . - , , . -, , LEGO, .



, , , .. . npm- . , SOLID. , , , . , .





SOLID. , , . .



. , . , , , . DRY, , , .



')

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



All Articles