рдЗрд╕рд▓рд┐рдП, рдЖрдкрдиреЗ рдПрдХ рдирдИ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдмрдирд╛рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред рдФрд░ рдпрд╣ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдПрдХ рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реИред рдПрдХ рдореВрд▓ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдмрдирд╛рдиреЗ рдореЗрдВ рдХрд┐рддрдирд╛ рд╕рдордп рд▓рдЧреЗрдЧрд╛? рдпрд╣ рдХрд┐рддрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ? рдПрдХ рдЖрдзреБрдирд┐рдХ рд╡реЗрдмрд╕рд╛рдЗрдЯ рдХреЛ рд╢реБрд░реБрдЖрдд рд╕реЗ рдХреНрдпрд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП?
рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЗ рд╕рд╛рде рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдмреЙрдпрд▓рд░рдкреНрд▓реЗрдЯ рдХреЛ рд░реЗрдЦрд╛рдВрдХрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВрдЧреЗ:
рд╣рдо рдХреНрдпрд╛ рдХрд╡рд░ рдХрд░реЗрдВрдЧреЗ:
- рдбреЙрдХ-рдХрдВрдкреЛрдЬрд╝ рдореЗрдВ рджреЗрд╡ рд╡рд╛рддрд╛рд╡рд░рдг рдХреА рд╕реНрдерд╛рдкрдирд╛ред
- рдлреНрд▓рд╛рд╕реНрдХ рдкрд░ рдмреИрдХреЗрдВрдб рдирд┐рд░реНрдорд╛рдгред
- рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдкрд░ рдПрдХ рджреГрд╢реНрдп рдмрдирд╛рдирд╛ред
- рд╡реЗрдмрдкреИрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ JS рдмрдирд╛рдПрдБред
- рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛, Redux рдФрд░ рд╕рд░реНрд╡рд░ рд╕рд╛рдЗрдб рд░реЗрдВрдбрд░рд┐рдВрдЧред
- RQ рдХреЗ рд╕рд╛рде рдХрд╛рд░реНрдп рдХрддрд╛рд░ред
рдкрд░рд┐рдЪрдп
рд╡рд┐рдХрд╛рд╕ рд╕реЗ рдкрд╣рд▓реЗ, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рдпрд╣ рддрдп рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдХреНрдпрд╛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ! рдЗрд╕ рд▓реЗрдЦ рдХреЗ рд▓рд┐рдП рдПрдХ рдореЙрдбрд▓ рдЖрд╡реЗрджрди рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВрдиреЗ рдПрдХ рдЖрджрд┐рдо рд╡рд┐рдХреА рдЗрдВрдЬрди рдмрдирд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдорд╛рд░реНрдХрдбрд╛рдЙрди рдореЗрдВ рдЬрд╛рд░реА рдХрд┐рдП рдЧрдП рдХрд╛рд░реНрдб рд╣реЛрдВрдЧреЗ; рдЙрдиреНрд╣реЗрдВ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ (рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдХрднреА-рдХрднреА) рд╕рдВрдкрд╛рджрди рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рд╕рдм рд╣рдо рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рд░реЗрдВрдбрд░рд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдПрдХ-рдкреЗрдЬ рдХреЗ рдЖрд╡реЗрджрди рдХреЗ рд░реВрдк рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВрдЧреЗ (рдЬреЛ рдХрд┐ рд╣рдорд╛рд░реЗ рднрд╡рд┐рд╖реНрдп рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЗ рдЯреЗрд░рд╛рдмрд╛рдЗрдЯреНрд╕ рдХреЛ рдЕрдиреБрдХреНрд░рдорд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд┐рд▓реНрдХреБрд▓ рдЖрд╡рд╢реНрдпрдХ рд╣реИ)ред
рдЖрдЗрдП рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдШрдЯрдХреЛрдВ рдкрд░ рдереЛрдбрд╝рд╛ рдФрд░ рд╡рд┐рд╕реНрддреГрдд рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:
- рдХреНрд▓рд╛рдЗрдВрдЯред рдЖрдЗрдП рд░рд┐рдПрдХреНрдЯ + рд░реЗрдбрдХреНрд╕ рдмрдВрдбрд▓ рдкрд░ рдПрдХ рдкреЗрдЬ рдХрд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдПрдВ (рдпрд╛рдиреА рдкреЗрдЬ рдЯреНрд░рд╛рдВрд╕рдХреНрд╢рди рдХреЗ рд╕рд╛рде AJAX рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ), рдЬреЛ рдлреНрд░рдВрдЯ-рдПрдВрдб рд╡рд░реНрд▓реНрдб рдореЗрдВ рдмрд╣реБрдд рд╣реА рд╕рд╛рдорд╛рдиреНрдп рд╣реИред
- рдЖрдЧреЗ рдХрд╛ рднрд╛рдЧ ред рдЖрдЗрдП рдПрдХ рд╕рд░рд▓ рдПрдХреНрд╕рдкреНрд░реЗрд╕ рд╕рд░реНрд╡рд░ рдмрдирд╛рдПрдВ рдЬреЛ рд╣рдорд╛рд░реЗ рд░рд┐рдПрдХреНрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдкреНрд░рд╕реНрддреБрдд рдХрд░реЗрдЧрд╛ (рдмреИрдХрдПрдВрдб рдореЗрдВ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдбреЗрдЯрд╛ рдХреЛ рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ рдЕрдиреБрд░реЛрдз рдХрд░рддреЗ рд╣реБрдП) рдФрд░ рдЗрд╕реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЬрд╛рд░реА рдХрд░реЗрдЧрд╛ред
- рдмреИрдХреЗрдВрдб ред рд╡реНрдпрд╛рдкрд╛рд░ рддрд░реНрдХ рдХреЗ рдорд╛рд╕реНрдЯрд░, рд╣рдорд╛рд░реЗ рдмреИрдХрдПрдВрдб рдПрдХ рдЫреЛрдЯрд╛ рдлреНрд▓рд╛рд╕реНрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реЛрдЧрд╛ред рд╣рдо рд▓реЛрдХрдкреНрд░рд┐рдп MongoDB рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рднрдВрдбрд╛рд░ рдореЗрдВ рдбреЗрдЯрд╛ (рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдб) рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВрдЧреЗ, рдФрд░ рдХрд╛рд░реНрдп рдХрддрд╛рд░ рдХреЗ рд▓рд┐рдП рдФрд░, рд╕рдВрднрд╡рддрдГ, рднрд╡рд┐рд╖реНрдп рдореЗрдВ, рдХреИрд╢рд┐рдВрдЧ рдореЗрдВ, рд╣рдо Redis рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред
- рдХрд╛рдо рдХрд░рдиреЗрд╡рд╛рд▓рд╛ ред рдЖрд░рдХреНрдпреВ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рджреНрд╡рд╛рд░рд╛ рднрд╛рд░реА рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдХрдВрдЯреЗрдирд░ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЗрдиреНрдлреНрд░рд╛рд╕реНрдЯреНрд░рдХреНрдЪрд░: рдЧрд┐рдЯ
рд╢рд╛рдпрдж, рд╣рдо рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ, рд▓реЗрдХрд┐рди, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╣рдо рдЧрд┐рдЯ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рд╡рд┐рдХрд╛рд╕ рдХрд╛ рд╕рдВрдЪрд╛рд▓рди рдХрд░реЗрдВрдЧреЗред
git init git remote add origin git@github.com:Saluev/habr-app-demo.git git commit --allow-empty -m "Initial commit" git push
(рдпрд╣рд╛рдВ рдЖрдкрдХреЛ рддреБрд░рдВрдд
.gitignore
рднрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред)
рдЕрдВрддрд┐рдо рдбреНрд░рд╛рдлреНрдЯ
рдЧрд┐рддреБрдм рдкрд░ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд▓реЗрдЦ рдХрд╛ рдкреНрд░рддреНрдпреЗрдХ рднрд╛рдЧ рдПрдХ рдкреНрд░рддрд┐рдмрджреНрдз рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ (рдореИрдВрдиреЗ рдЗрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдзрд┐рдХ рдкреБрдирд░реНрдЬрдиреНрдо рдХрд┐рдпрд╛!)ред
рдЗрдиреНрдлреНрд░рд╛рд╕реНрдЯреНрд░рдХреНрдЪрд░: docker- рд░рдЪрдирд╛
рдЖрдЗрдП рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдХреЗ рд╢реБрд░реВ рдХрд░реЗрдВред рдШрдЯрдХреЛрдВ рдХреА рдкреНрд░рдЪреБрд░рддрд╛ рдХреЗ рд╕рд╛рде рдЬреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣реИ, рдмрд╣реБрдд рддрд╛рд░реНрдХрд┐рдХ рд╡рд┐рдХрд╛рд╕ рд╕рдорд╛рдзрд╛рди рдХреЗ рд▓рд┐рдП docker-compose рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
рдирд┐рдореНрди рд╕рд╛рдордЧреНрд░реА рдХреЗ
docker-compose.yml
рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ
docker-compose.yml
рдлрд╝рд╛рдЗрд▓ рдЬреЛрдбрд╝реЗрдВ:
version: '3' services: mongo: image: "mongo:latest" redis: image: "redis:alpine" backend: build: context: . dockerfile: ./docker/backend/Dockerfile environment: - APP_ENV=dev depends_on: - mongo - redis ports: - "40001:40001" volumes: - .:/code frontend: build: context: . dockerfile: ./docker/frontend/Dockerfile environment: - APP_ENV=dev - APP_BACKEND_URL=backend:40001 - APP_FRONTEND_PORT=40002 depends_on: - backend ports: - "40002:40002" volumes: - ./frontend:/app/src worker: build: context: . dockerfile: ./docker/worker/Dockerfile environment: - APP_ENV=dev depends_on: - mongo - redis volumes: - .:/code
рдпрд╣рд╛рдБ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓рддреЗ рд╣реИрдВред
- рдПрдХ MongoDB рдХрдВрдЯреЗрдирд░ рдФрд░ рдПрдХ рд░реЗрдбрд┐рд╕ рдХрдВрдЯреЗрдирд░ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
- рд╣рдорд╛рд░реЗ рдмреИрдХрдПрдВрдб рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдВрдЯреЗрдирд░ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ (рдЬрд┐рд╕рдХрд╛ рд╣рдо рдиреАрдЪреЗ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ)ред рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ APP_ENV = рджреЗрд╡ рдЗрд╕реЗ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ (рд╣рдо рдЗрд╕реЗ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рдлреНрд▓рд╛рд╕реНрдХ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЛ рдХреНрдпрд╛ рд▓реЛрдб рдХрд░рдирд╛ рд╣реИ), рдФрд░ рдЗрд╕рдХрд╛ рдкреЛрд░реНрдЯ 40001 рдмрд╛рд╣рд░ рдЦреБрд▓реЗрдЧрд╛ (рдЗрд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╣рдорд╛рд░рд╛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдПрдкреАрдЖрдИ рдкрд░ рдЬрд╛рдПрдЧрд╛)ред
- рд╣рдорд╛рд░реЗ рдлреНрд░рдВрдЯреЗрдВрдб рдХрд╛ рдПрдХ рдХрдВрдЯреЗрдирд░ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рднреА рдЗрд╕рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ, рдЬреЛ рдмрд╛рдж рдореЗрдВ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрдВрдЧреЗ, рдФрд░ рдкреЛрд░реНрдЯ 40002 рдЦреБрд▓рддрд╛ рд╣реИред рдпрд╣ рд╣рдорд╛рд░реЗ рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдореБрдЦреНрдп рдкреЛрд░реНрдЯ рд╣реИ: рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рд╣рдо http: // localhost: 40002 рдкрд░ рдЬрд╛рдПрдВрдЧреЗред
- рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХрд╛ рдХрдВрдЯреЗрдирд░ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЙрд╕реЗ рдмрд╛рд╣рд░реА рдмрдВрджрд░рдЧрд╛рд╣реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдФрд░ рдХреЗрд╡рд▓ MongoDB рдФрд░ Redis рдореЗрдВ рдПрдХреНрд╕реЗрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдЕрдм dockerfiles рдмрдирд╛рддреЗ рд╣реИрдВред рдЕрднреА, рдбреЙрдХрд░ рдХреЗ рдмрд╛рд░реЗ
рдореЗрдВ рдЙрддреНрдХреГрд╖реНрдЯ рд▓реЗрдЦреЛрдВ рдХреЗ рдЕрдиреБрд╡рд╛рдж рдХреА рдПрдХ
рд╢реНрд░реГрдВрдЦрд▓рд╛ рд╣реИрдмреЗрд░рд╛ рдореЗрдВ рдЖ рд░рд╣реА рд╣реИ - рдЖрдк рд╕рднреА рд╡рд┐рд╡рд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рд╡рд╣рд╛рдВ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред
рдЪрд▓реЛ рдмреИрдХрдПрдВрдб рд╕реЗ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред
# docker/backend/Dockerfile FROM python:stretch COPY requirements.txt /tmp/ RUN pip install -r /tmp/requirements.txt ADD . /code WORKDIR /code CMD gunicorn -w 1 -b 0.0.0.0:40001 --worker-class gevent backend.server:app
рдпрд╣ рд╕рдордЭрд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдо gunicorn рдлреНрд▓рд╛рд╕реНрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЪрд▓рд╛рддреЗ рд╣реИрдВ, рдЬреЛ рдмреИрдХрдПрдВрдб.рд╕рд░реНрд╡рд░ рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рдирд╛рдо
app
рдиреАрдЪреЗ рдЫрд┐рдкрд╛ рд╣реИред
рдХреЛрдИ рдХрдо рдорд╣рддреНрд╡рдкреВрд░реНрдг
docker/backend/.dockerignore
:
.git .idea .logs .pytest_cache frontend tests venv *.pyc *.pyo
рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдЖрдо рддреМрд░ рдкрд░ рдмреИрдХрдПрдВрдб рдХреЗ рд╕рдорд╛рди рд╣реЛрддрд╛ рд╣реИ, рдХреЗрд╡рд▓ рдЕрдВрдЧрд░рдЦрд╛ рдХреЗ рдмрдЬрд╛рдп рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдкрд┐рдЯ рдореЙрдбреНрдпреВрд▓ рдХрд╛ рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рдХреНрд╖реЗрдкрдг рд╣реЛрддрд╛ рд╣реИ:
# docker/worker/Dockerfile FROM python:stretch COPY requirements.txt /tmp/ RUN pip install -r /tmp/requirements.txt ADD . /code WORKDIR /code CMD python -m worker
рд╣рдо рд╕рднреА рдХрд╛рд░реНрдп
worker/__main__.py
ред
.dockerignore
рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ
.dockerignore
рдмреИрдХрдПрдВрдб рдХреЗ рд╕рдорд╛рди рд╣реИред
рдЕрдВрдд рдореЗрдВ, рджреГрд╢реНрдпред рд╣реИрдмреЗ рдкрд░ рдЙрдирдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ
рдЕрд▓рдЧ рд▓реЗрдЦ рд╣реИ , рд▓реЗрдХрд┐рди рд╕реНрдЯреИрдХрдУрд╡рд░рдлреНрд▓реЛ рдкрд░
рд╡реНрдпрд╛рдкрдХ рдЪрд░реНрдЪрд╛ рдФрд░ "рджреЛрд╕реНрддреЛрдВ рдХреА рднрд╛рд╡рдирд╛ рдореЗрдВ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рд╕реЗ рджреЗрдЦрддреЗ рд╣реБрдП, рдХреНрдпрд╛ рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА 2018 рд╣реИ, рдХреНрдпрд╛ рдЕрднреА рднреА рдХреЛрдИ рд╕рд╛рдорд╛рдиреНрдп рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИ?" рд╡рд╣рд╛рдВ рд╕рдм рдХреБрдЫ рдЗрддрдирд╛ рд╕рд░рд▓ рдирд╣реАрдВ рд╣реИред рдореИрдВ рдбреЙрдХ рдлрд╝рд╛рдЗрд▓ рдХреЗ рдЗрд╕ рд╕рдВрд╕реНрдХрд░рдг рдкрд░ рдмрд╕ рдЧрдпрд╛ред
# docker/frontend/Dockerfile FROM node:carbon WORKDIR /app # package.json package-lock.json npm install, . COPY frontend/package*.json ./ RUN npm install # , # PATH. ENV PATH /app/node_modules/.bin:$PATH # . ADD frontend /app/src WORKDIR /app/src RUN npm run build CMD npm run start
рдкреЗрд╢реЗрд╡рд░реЛрдВ:
- рд╕рдм рдХреБрдЫ рдЕрдкреЗрдХреНрд╖рд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдХреИрд╢ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ (рдиреАрдЪреЗ рдХреА рдкрд░рдд рдкрд░ - рдирд┐рд░реНрднрд░рддрд╛рдПрдВ, рд╢реАрд░реНрд╖ рдкрд░ - рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХрд╛ рдирд┐рд░реНрдорд╛рдг);
docker-compose exec frontend npm install --save newDependency
рдХрд╛рдо рдХрд░рддреА рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╣рдорд╛рд░реЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ docker-compose exec frontend npm install --save newDependency
рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рддрд╛ рд╣реИ (рдЬреЛ рдХрд┐ рдЕрдЧрд░ рд╣рдо COPY рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ, рддреЛ рдмрд╣реБрдд рд╕реЗ рд▓реЛрдЧ рд╕реБрдЭрд╛рд╡ рджреЗрддреЗ рд╣реИрдВ)ред рд╡реИрд╕реЗ рднреА npm install --save newDependency
рдХреЛ рдХрдВрдЯреЗрдирд░ рдХреЗ рдмрд╛рд╣рд░ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣ рд╡рд╛рдВрдЫрдиреАрдп рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдирдП рдкреИрдХреЗрдЬ рдХреА рдХреБрдЫ рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рдкрд╣рд▓реЗ рд╕реЗ рдореМрдЬреВрдж рд╣реЛ рд╕рдХрддреА рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдПрдХ рдЕрд▓рдЧ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдХреЗ рддрд╣рдд рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ (docker рдХреЗ рдЕрдВрджрд░ рдПрдХ рдФрд░ рд╣рдорд╛рд░реЗ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓реЗ macbook рдХреЗ рддрд╣рдд рдирд╣реАрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП ), рдФрд░ рдлрд┐рд░ рднреА рд╣рдо рдЖрдо рддреМрд░ рдкрд░ рд╡рд┐рдХрд╛рд╕ рдорд╢реАрди рдкрд░ рдиреЛрдб рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдПрдХ рдбреЙрдХрд░ рдЙрди рд╕рднреА рдкрд░ рд░рд╛рдЬ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП!
рдЦреИрд░ рдФрд░ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ
docker/frontend/.dockerignore
:
.git .idea .logs .pytest_cache backend worker tools node_modules npm-debug tests venv
рддреЛ, рд╣рдорд╛рд░рд╛ рдХрдВрдЯреЗрдирд░ рдлреНрд░реЗрдо рддреИрдпрд╛рд░ рд╣реИ рдФрд░ рдЖрдк рдЗрд╕реЗ рд╕рд╛рдордЧреНрд░реА рд╕реЗ рднрд░ рд╕рдХрддреЗ рд╣реИрдВ!
рдмреИрдХрдПрдВрдб: рдлреНрд▓рд╛рд╕реНрдХ рдлреНрд░реЗрдорд╡рд░реНрдХ
рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП
flask
,
flask-cors
,
gunicorn
рдФрд░
gunicorn
рдЬреЛрдбрд╝реЗрдВред
gunicorn
рдФрд░
backend/server.py
gunicorn
рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдлреНрд▓рд╛рд╕реНрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдПрдВред
рд╣рдордиреЗ рдлреНрд▓рд╛рд╕реНрдХ рдХреЛ
backend.{env}_settings
рдлрд╝рд╛рдЗрд▓ рд╕реЗ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдЦреАрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛
backend.{env}_settings
, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╣рдореЗрдВ рд╣рд░ рдЪреАрдЬрд╝ рдХреЛ
backend/dev_settings.py
рд▓рд┐рдП рдПрдХ (рдХрдо рд╕реЗ рдХрдо рдЦрд╛рд▓реА) рдлрд╝рд╛рдЗрд▓
backend/dev_settings.py
рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред
рдЕрдм рд╣рдо рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рддреМрд░ рдкрд░ рд╣рдорд╛рд░реЗ рдмреИрдХрдПрдВрдб рдХреЛ рдмрдврд╝рд╛ рд╕рдХрддреЗ рд╣реИрдВ!
habr-app-demo$ docker-compose up backend ... backend_1 | [2019-02-23 10:09:03 +0000] [6] [INFO] Starting gunicorn 19.9.0 backend_1 | [2019-02-23 10:09:03 +0000] [6] [INFO] Listening at: http://0.0.0.0:40001 (6) backend_1 | [2019-02-23 10:09:03 +0000] [6] [INFO] Using worker: gevent backend_1 | [2019-02-23 10:09:03 +0000] [9] [INFO] Booting worker with pid: 9
рд╣рдо рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВред
рд╕реАрдорд╛рд╡рд░реНрддреА: рдПрдХреНрд╕рдкреНрд░реЗрд╕ рд░реВрдкрд░реЗрдЦрд╛
рдЖрдЗрдП рдкреИрдХреЗрдЬ рдмрдирд╛рдХрд░ рд╢реБрд░реБрдЖрдд рдХрд░реЗрдВред рдлреНрд░рдВрдЯрдПрдВрдб рдлреЛрд▓реНрдбрд░
npm init
рдФрд░ рдЙрд╕рдореЗрдВ
npm init
рдЪрд▓рд╛рдХрд░, рдХреБрдЫ рдЕрдкрд░рд┐рд╣рд╛рд░реНрдп рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рдмрд╛рдж, рд╣рдореЗрдВ рддреИрдпрд╛рд░ рдкреИрдХреЗрдЬ рдорд┐рд▓рддрд╛ рд╣реИред рдЖрддреНрдорд╛ рдореЗрдВ рдЯреИрдЧ рдХрд░реЗрдВ
{ "name": "habr-app-demo", "version": "0.0.1", "description": "This is an app demo for Habr article.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git+https://github.com/Saluev/habr-app-demo.git" }, "author": "Tigran Saluev <tigran@saluev.com>", "license": "MIT", "bugs": { "url": "https://github.com/Saluev/habr-app-demo/issues" }, "homepage": "https://github.com/Saluev/habr-app-demo#readme" }
рднрд╡рд┐рд╖реНрдп рдореЗрдВ, рд╣рдореЗрдВ рдбреЗрд╡рд▓рдкрд░ рдХреА рдорд╢реАрди рдкрд░ Node.js рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ (рд╣рд╛рд▓рд╛рдВрдХрд┐ рд╣рдо рдЕрднреА рднреА рдЪрдХрдорд╛ рджреЗ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдбреЙрдХрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ
npm init
рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдУрд╣ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ)ред
Dockerfile
рд╣рдордиреЗ
Dockerfile
npm run build
рдФрд░
npm run start
npm run build
рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рд╣реИ - рдЖрдкрдХреЛ
package.json
рдореЗрдВ рдЙрдкрдпреБрдХреНрдд рдХрдорд╛рдВрдб рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
Dockerfile
:
build
рдХрдорд╛рдВрдб рдЕрднреА рддрдХ рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЕрднреА рднреА рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрдЧрд╛ред
рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдирд┐рд░реНрднрд░рддрд╛ рдЬреЛрдбрд╝реЗрдВ рдФрд░
index.js
рдореЗрдВ рдПрдХ рд╕рд░рд▓ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдмрдирд╛рдПрдВ:
рдЕрдм
docker-compose up frontend
рд╣рдорд╛рд░реЗ рд╕реАрдиреНрд╕ рдХреЛ рдмрдврд╝рд╛рддрд╛ рд╣реИ! рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛,
http: // localhost: 40002 рдкрд░ , рдХреНрд▓рд╛рд╕рд┐рдХ "рд╣реИрд▓реЛ, рджреБрдирд┐рдпрд╛" рдкрд╣рд▓реЗ рд╣реА рджрд┐рдЦрд╛рд╡рд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рд╕реАрдорд╛: рд╡реЗрдмрдкреИрдХ рдФрд░ рд░рд┐рдПрдХреНрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдирд┐рд░реНрдорд╛рдг
рдпрд╣ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдореЗрдВ рд╕рд╛рджреЗ рдкрд╛рда рд╕реЗ рдЕрдзрд┐рдХ рдХреБрдЫ рдЪрд┐рддреНрд░рд┐рдд рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред рдЗрд╕ рдЕрдиреБрднрд╛рдЧ рдореЗрдВ, рд╣рдо
App
рдХрд╛ рд╕рдмрд╕реЗ рд╕рд░рд▓ рд░рд┐рдПрдХреНрдЯ рдШрдЯрдХ рдЬреЛрдбрд╝реЗрдВрдЧреЗ рдФрд░ рдЕрд╕реЗрдВрдмрд▓реА рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВрдЧреЗред
рдЬрдм рд░рд┐рдПрдХреНрдЯ рдореЗрдВ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдлреЙрд░реНрдо рдХреЗ рд╕рд┐рдВрдЯреИрдХреНрдЯрд┐рдХ рдХрдВрд╕реНрдЯреНрд░рдХреНрд╢рди рджреНрд╡рд╛рд░рд╛ рд╡рд┐рд╕реНрддрд╛рд░рд┐рдд рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреА рдПрдХ рдмреЛрд▓реА
JSX рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ
render() { return <MyButton color="blue">{this.props.caption}</MyButton>; }
рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЗрдВрдЬрди рдЗрд╕реЗ рдирд╣реАрдВ рд╕рдордЭрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдЖрдорддреМрд░ рдкрд░ рдмрд┐рд▓реНрдб рдЪрд░рдг рдХреЛ рдлреНрд░рдВрдЯреЗрдВрдб рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИред рд╡рд┐рд╢реЗрд╖ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕рдВрдХрд▓рдХ (рд╣рд╛рдБ-рд╣рд╛рдБ) рдмрджрд▓реА рд╣реБрдИ рдХреНрд▓рд╛рд╕рд┐рдХ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рд╕рд┐рдВрдЯреИрдХреНрдЯрд┐рдХ рдЪреАрдиреА рдХреЛ рдЪрд╛рд▓реВ рдХрд░рддреЗ рд╣реИрдВ, рдЖрдпрд╛рддреЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓рддреЗ рд╣реИрдВ, рдЫреЛрдЯрд╛ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реА рддрд░рд╣ред
2014 рд╕рд╛рд▓ред apt-cache search рдЬрд╛рд╡рд╛рддреЛ, рд╕рдмрд╕реЗ рд╕рд░рд▓ рд░рд┐рдПрдХреНрдЯ рдШрдЯрдХ рдмрд╣реБрдд рд╕рд░рд▓ рджрд┐рдЦрддрд╛ рд╣реИред
рд╡рд╣ рдмрд╕ рдПрдХ рдЕрдзрд┐рдХ рдареЛрд╕ рдкрд┐рди рдХреЗ рд╕рд╛рде рд╣рдорд╛рд░реЗ рдЕрднрд┐рд╡рд╛рджрди рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдЧрд╛ред
рд╣рдорд╛рд░реЗ рднрд╡рд┐рд╖реНрдп рдХреЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреА рдиреНрдпреВрдирддрдо HTML рд░реВрдкрд░реЗрдЦрд╛ рдпреБрдХреНрдд рдлрд╝рд╛рдЗрд▓
frontend/src/template.js
рдЬреЛрдбрд╝реЗрдВ:
рдПрдХ рдЧреНрд░рд╛рд╣рдХ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдмрд┐рдВрджреБ рдЬреЛрдбрд╝реЗрдВ:
рдЗрд╕ рд╕рднреА рд╕реБрдВрджрд░рддрд╛ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдП:
рд╡реЗрдмрдкреИрдХ рдЬреЗрдПрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдлреИрд╢рдиреЗрдмрд▓ рдпреБрд╡рд╛
рдмрд┐рд▓реНрдбрд░ рд╣реИ (рд╣рд╛рд▓рд╛рдВрдХрд┐ рдореИрдВрдиреЗ рддреАрди рдШрдВрдЯреЗ рдХреЗ рд▓рд┐рдП рджреГрд╢реНрдпрдкрдЯрд▓ рдкрд░ рд▓реЗрдЦ рдирд╣реАрдВ рдкрдврд╝рд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдлреИрд╢рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд┐рд╢реНрдЪрд┐рдд рдирд╣реАрдВ рд╣реВрдВ);
рдЬреЗрдПрд╕рдПрдХреНрд╕ рдЬреИрд╕реЗ рд╕рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓реЛрд╢рди рдХреЗ рд▓рд┐рдП
рдмреИрдмрд▓ рдПрдХ рдХрдВрдкрд╛рдЗрд▓рд░ рд╣реИ, рдФрд░ рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рд╕рднреА IE рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреЙрд▓реАрдлрд╝рд┐рд▓ рдкреНрд░рджрд╛рддрд╛ рд╣реИред
рдпрджрд┐ рдлреНрд░рдВрдЯрдПрдВрдб рдХрд╛ рдкрд┐рдЫрд▓рд╛ рдЪрд▓рдирд╛ рдЕрднреА рднреА рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдмрд╕ рдЗрддрдирд╛ рдХрд░рдирд╛ рд╣реИ
docker-compose exec frontend npm install --save \ react \ react-dom docker-compose exec frontend npm install --save-dev \ webpack \ webpack-cli \ babel-loader \ @babel/core \ @babel/polyfill \ @babel/preset-env \ @babel/preset-react
рдирдИ рдирд┐рд░реНрднрд░рддрд╛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рдЕрдм рд╡реЗрдмрдкреИрдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ:
frontend/.babelrc
рдХрд╛рд░реНрдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ
frontend/.babelrc
рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
{ "presets": ["@babel/env", "@babel/react"] }
рдЕрдВрдд рдореЗрдВ, рд╣рдорд╛рд░реЗ
npm run build
рдХрдорд╛рдВрдб рдХреЛ рд╕рд╛рд░реНрдердХ рдмрдирд╛рдПрдВ:
// frontend/package.json ... "scripts": { "build": "webpack", "start": "node /app/server.js", "test": "echo \"Error: no test specified\" && exit 1" }, ...
рдЕрдм рд╣рдорд╛рд░рд╛ рдореБрд╡рдХреНрдХрд┐рд▓, рдкреЙрд▓реАрдлрд╝рд┐рд▓реНрд╕ рдФрд░ рдЙрд╕рдХреЗ рд╕рднреА рдЖрд╢реНрд░рд┐рддреЛрдВ рдХреЗ рдПрдХ рдмрдВрдбрд▓ рдХреЗ рд╕рд╛рде, рдмреЗрдмрд▓,
../dist/client.js
рдФрд░ рд╕рд┐рд▓рд╡рдЯреЛрдВ рдХреЛ рдПрдХ рдЕрдЦрдВрдб
../dist/client.js
рдлрд╝рд╛рдЗрд▓ рдореЗрдВ
../dist/client.js
ред рдЗрд╕реЗ рд╣рдорд╛рд░реЗ рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдПрдХ рд╕реНрдерд┐рд░ рдлрд╝рд╛рдЗрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝реЗрдВ, рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдорд╛рд░реНрдЧ рдореЗрдВ рд╣рдо рдЕрдкрдирд╛ HTML рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджреЗрдВрдЧреЗ:
рд╕рдлрд▓рддрд╛! рдЕрдм, рдпрджрд┐ рд╣рдо
docker-compose up --build frontend
рдЪрд▓рд╛рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо "рд╣реЗрд▓реЛ, рд╡рд░реНрд▓реНрдб!" рджреЗрдЦреЗрдВрдЧреЗред рдПрдХ рдирдП, рдЪрдордХрджрд╛рд░ рдЖрд╡рд░рдг рдореЗрдВ, рдФрд░ рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ React Developer Tools рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╕реНрдерд╛рдкрд┐рдд рд╣реИ (
Chrome ,
Firefox ), рддреЛ рдбреЗрд╡рд▓рдкрд░ рдЯреВрд▓ рдореЗрдВ рдПрдХ React рдШрдЯрдХ рдЯреНрд░реА рднреА рд╣реИ:

рдмреИрдХрдПрдВрдб: MongoDB рдореЗрдВ рдбреЗрдЯрд╛
рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдореЗрдВ рдЬреАрд╡рди рдХреЛ рдЖрдЧреЗ рдмрдврд╝рд╛рдиреЗ рдФрд░ рд╕рд╛рдБрд╕ рд▓реЗрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рдЗрд╕реЗ рдмреИрдХрдПрдВрдб рдореЗрдВ рд╕рд╛рдБрд╕ рд▓реЗрдирд╛ рдЪрд╛рд╣рд┐рдПред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдорд╛рд░реНрдХрдбрд╛рдЙрди рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд┐рдП рдЧрдП рдХрд╛рд░реНрдб рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рдереЗ - рдпрд╣ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред
рдЬрдмрдХрд┐
рдЕрдЬрдЧрд░ рдореЗрдВ MongoDB рдХреЗ рд▓рд┐рдП рдУрдЖрд░рдПрдо рд╣реИрдВ , рдореИрдВ рдУрдЖрд░рдПрдо рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЛ рд╢рд╛рддрд┐рд░ рдорд╛рдирддрд╛ рд╣реВрдВ рдФрд░ рдореИрдВ рдЖрдкрдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╕рдорд╛рдзрд╛рдиреЛрдВ рдХрд╛ рдЕрдзреНрдпрдпрди рдЫреЛрдбрд╝ рджреЗрддрд╛ рд╣реВрдВред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рд╣рдо рдХрд╛рд░реНрдб рдФрд░ рд╕рд╛рде рд╡рд╛рд▓реЗ
рдбреАрдПрдУ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╡рд░реНрдЧ рдмрдирд╛рдПрдВрдЧреЗ:
(рдпрджрд┐ рдЖрдк рдЕрднреА рднреА рдкрд╛рдпрдерди рдореЗрдВ рдЯрд╛рдЗрдк рдПрдиреЛрдЯреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ
рдЗрди рд▓реЗрдЦреЛрдВ рдХреЛ рдЕрд╡рд╢реНрдп рджреЗрдЦреЗрдВ!)
рдЕрдм рдЪрд▓рд┐рдП
CardDAO
рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдмрдирд╛рддреЗ рд╣реИрдВ рдЬреЛ
pymongo
рд╕реЗ
Database
рдСрдмреНрдЬреЗрдХреНрдЯ рд▓реЗрддрд╛ рд╣реИ (рд╣рд╛рдБ,
pymongo
рдХреЛ
requirements.txt
рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдордпред
pymongo
):
рдмреИрдХрдПрдВрдб рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рдореЛрдВрдЧрд╛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдХрд╛ рд╕рдордпред рд╣рдордиреЗ рдЕрдкрдиреЗ рдХрдВрдЯреЗрдирд░ рдХрд╛ рдирд╛рдо рдореЛрдВрдЧреЛ
mongo
рд╕рд╛рде рд░рдЦрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП
MONGO_HOST = "mongo"
рдЕрдм рд╣рдореЗрдВ
MongoCardDAO
рдмрдирд╛рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ рдФрд░ рдлреНрд▓рд╛рд╕реНрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рд╣рд╛рд▓рд╛рдБрдХрд┐ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ (рд╕реЗрдЯрд┐рдВрдЧреНрд╕ тЖТ pymongo рдХреНрд▓рд╛рдЗрдВрдЯ тЖТ pymongo рдбреЗрдЯрд╛рдмреЗрд╕ тЖТ
MongoCardDAO
) рдХреА рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рдкрджрд╛рдиреБрдХреНрд░рдо рд╣реИ, рдЪрд▓реЛ рддреБрд░рдВрдд рдПрдХ рдХреЗрдВрджреНрд░реАрдХреГрдд рд░рд╛рдЬрд╛ рдШрдЯрдХ рдмрдирд╛рддреЗ рд╣реИрдВ рдЬреЛ
рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рдХрд░рддрд╛
рд╣реИ (рдпрд╣ рдлрд┐рд░ рд╕реЗ рдХрд╛рдо рдореЗрдВ рдЖрдПрдЧрд╛ рдЬрдм рд╣рдо рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдФрд░ рдЯреВрд▓ рдХрд░рддреЗ рд╣реИрдВ)ред
рдлреНрд▓рд╛рд╕реНрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдПрдХ рдирдпрд╛ рдорд╛рд░реНрдЧ рдЬреЛрдбрд╝рдиреЗ рдФрд░ рджреГрд╢реНрдп рдХрд╛ рдЖрдирдВрдж рд▓реЗрдиреЗ рдХрд╛ рд╕рдордп!
docker-compose up --build backend
рд╕рд╛рде рдкреБрдирдГ рдЖрд░рдВрдн рдХрд░реЗрдВ:

рдЙрдлрд╝тАж рдУрд╣, рдмрд┐рд▓реНрдХреБрд▓ред рд╣рдореЗрдВ рд╕рд╛рдордЧреНрд░реА рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ! рд╣рдо рдЯреВрд▓ рдлрд╝реЛрд▓реНрдбрд░ рдХреЛ рдЦреЛрд▓реЗрдВрдЧреЗ рдФрд░ рдЙрд╕рдореЗрдВ рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЬреЛрдбрд╝реЗрдВрдЧреЗ рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдЯреЗрд╕реНрдЯ рдХрд╛рд░реНрдб рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛:
docker-compose exec backend python -m tools.add_test_content
рд╣рдорд╛рд░реЗ рдореЛрдВрдЧрд╛ рдХреЛ
docker-compose exec backend python -m tools.add_test_content
рдХрдВрдЯреЗрдирд░ рдХреЗ рдЕрдВрджрд░ рд╕реЗ рд╕рд╛рдордЧреНрд░реА рд╕реЗ рднрд░
docker-compose exec backend python -m tools.add_test_content
ред

рд╕рдлрд▓рддрд╛! рдЕрдм рд╕рд╛рдордиреЗ рдХреЗ рдЫреЛрд░ рдкрд░ рдЗрд╕рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред
рд╕реАрдорд╛рд╡рд░реНрддреА: Redux
рдЕрдм рд╣рдо рд░реВрдЯ
/card/:id_or_slug
рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╣рдорд╛рд░рд╛ рд░рд┐рдПрдХреНрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЦреБрд▓ рдЬрд╛рдПрдЧрд╛, рдПрдкреАрдЖрдИ рд╕реЗ рдХрд╛рд░реНрдб рдбреЗрдЯрд╛ рд▓реЛрдб рдХрд░реЗрдВ рдФрд░ рдЗрд╕реЗ рд╣рдореЗрдВ рдХрд┐рд╕реА рднреА рддрд░рд╣ рджрд┐рдЦрд╛рдПрдВред рдФрд░ рдпрд╣рд╛рдВ, рд╢рд╛рдпрдж, рд╕рдмрд╕реЗ рдХрдард┐рди рд╣рд┐рд╕реНрд╕рд╛ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рд╕рд░реНрд╡рд░ рддреБрд░рдВрдд рд╣рдореЗрдВ рдХрд╛рд░реНрдб рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде HTML рджреЗ, рдЕрдиреБрдХреНрд░рдордг рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ, рдЬрдм рдЖрд╡реЗрджрди рдХрд╛рд░реНрдб рдХреЗ рдмреАрдЪ рдиреЗрд╡рд┐рдЧреЗрдЯ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдПрдкреАрдЖрдИ рд╕реЗ JSON рдХреЗ рд░реВрдк рдореЗрдВ рд╕рднреА рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдкреГрд╖реНрда рдЕрдзрд┐рднрд╛рд░ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред рдФрд░ рдЗрд╕рд▓рд┐рдП рдпрд╣ рд╕рдм - рдмрд┐рдирд╛ рдХреЙрдкреА-рдкреЗрд╕реНрдЯ рдХреЗ!
Redux рдХреЛ рдЬреЛрдбрд╝рдХрд░ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред Redux рд░рд╛рдЬреНрдп рднрдВрдбрд╛рд░рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИред рд╡рд┐рдЪрд╛рд░ рдпрд╣ рд╣реИ рдХрд┐ рд╣рдЬрд╛рд░ рдирд┐рд╣рд┐рдд рдХреЗ рдмрдЬрд╛рдп рдпрд╣ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдФрд░ рдЕрдиреНрдп рджрд┐рд▓рдЪрд╕реНрдк рдШрдЯрдирд╛рдУрдВ рдХреЗ рджреМрд░рд╛рди рдЖрдкрдХреЗ рдШрдЯрдХ рдмрджрд▓ рдЬрд╛рддреЗ рд╣реИрдВ, рдЙрдирдХреЗ рдкрд╛рд╕ рдПрдХ рдХреЗрдВрджреНрд░реАрдХреГрдд рд╕реНрдерд┐рддрд┐ рд╣реЛрддреА рд╣реИ, рдФрд░ рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рдХреЗрдВрджреНрд░реАрдХреГрдд рддрдВрддреНрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХреЛрдИ рднреА рдкрд░рд┐рд╡рд░реНрддрди рд╣реЛрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЕрдЧрд░ рдкрд╣рд▓реЗ рдиреЗрд╡рд┐рдЧреЗрд╢рди рдХреЗ рд▓рд┐рдП рд╣рдо рдкрд╣рд▓реЗ рд▓реЛрдбрд┐рдВрдЧ GIF рдХреЛ рдЪрд╛рд▓реВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдордиреЗ AJAX рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХ рдЕрдиреБрд░реЛрдз рдХрд┐рдпрд╛ рдФрд░, рдЖрдЦрд┐рд░рдХрд╛рд░, рд╕рдлрд▓рддрд╛ рдХреЙрд▓рдмреИрдХ рдореЗрдВ, рд╣рдордиреЗ рдкреГрд╖реНрда рдХреЗ рдЖрд╡рд╢реНрдпрдХ рднрд╛рдЧреЛрдВ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛, рдлрд┐рд░ Redux рдкреНрд░рддрд┐рдорд╛рди рдореЗрдВ рд╣рдореЗрдВ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреЛ рдПрдиреАрдореЗрд╢рди рдХреЗ рд╕рд╛рде рдЬреАрдЖрдИрдПрдл рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдордВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, " рд╡реИрд╢реНрд╡рд┐рдХ рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрджрд▓ рджреЗрдЧрд╛ рддрд╛рдХрд┐ рдЖрдкрдХрд╛ рдПрдХ рдШрдЯрдХ рдкрд┐рдЫрд▓реА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдмрд╛рд╣рд░ рдирд┐рдХрд╛рд▓ рджреЗ рдФрд░ рдПрдиреАрдореЗрд╢рди рдбрд╛рд▓ рджреЗ, рдлрд┐рд░ рдПрдХ рдЕрдиреБрд░реЛрдз рдХрд░реЗрдВ, рдФрд░ рдЗрд╕рдХреА рд╕рдлрд▓рддрд╛ рдХреЗ рдХреЙрд▓рдмреИрдХ рдореЗрдВ рдПрдХ рдФрд░ рдХрд╛рд░реНрд░рд╡рд╛рдИ рднреЗрдЬреЗрдВ, "рд╕рд╛рдордЧреНрд░реА рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрджрд▓реЗрдВ"ред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдЕрдм рд╣рдо рдЗрд╕реЗ рд╕реНрд╡рдпрдВ рджреЗрдЦреЗрдВрдЧреЗред
рдЪрд▓реЛ рд╣рдорд╛рд░реЗ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдирдИ рдирд┐рд░реНрднрд░рддрд╛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдХреЗ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред
docker-compose exec frontend npm install --save \ redux \ react-redux \ redux-thunk \ redux-devtools-extension
рдкрд╣рд▓рд╛, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, Redux рд╣реИ, рджреВрд╕рд░рд╛ рд░рд┐рдПрдХреНрдЯ рдФрд░ Redux (рд╡рд┐рд╢реЗрд╖рдЬреНрдЮреЛрдВ рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдЦрд┐рдд) рдХреЛ рдкрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рд╢реЗрд╖ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИ, рддреАрд╕рд░рд╛ рдПрдХ рдмрд╣реБрдд рд╣реА рдЖрд╡рд╢реНрдпрдХ рдЪреАрдЬ рд╣реИ, рдЬрд┐рд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛
рдЗрд╕рдХреЗ README рдореЗрдВ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдЙрдЪрд┐рдд рд╣реИ, рдФрд░, рдЖрдЦрд┐рд░рдХрд╛рд░,
Redux DevTools рдХреЛ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдЪреМрдереА рд╣реИред
рд╡рд┐рд╕реНрддрд╛рд░ ред
рдЪрд▓реЛ рдмреЙрдпрд▓рд░рдкреНрд▓реЗрдЯ Redux рдХреЛрдб рд╕реЗ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ: рдПрдХ reducer рдмрдирд╛рддреЗ рд╣реИрдВ рдЬреЛ рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд░рд╛рдЬреНрдп рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддрд╛ рд╣реИред
рд╣рдорд╛рд░рд╛ рдЧреНрд░рд╛рд╣рдХ рдереЛрдбрд╝рд╛ рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИ, Redux рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд╛рдирд╕рд┐рдХ рд░реВрдк рд╕реЗ рддреИрдпрд╛рд░ рд╣реЛрддрд╛ рд╣реИ:
рдЕрдм рд╣рдо рдбреЙрдХрдЯрд░-рдХрдВрдкреЛрдЬрд╝ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдХреЛрдИ рднреА рдЪреАрдЬрд╝ рдЯреВрдЯреА рдирд╣реАрдВ рд╣реИ, рдФрд░ рд╣рдорд╛рд░реА рдЖрджрд┐рдо рд╕реНрдерд┐рддрд┐ Redux DevTools рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрддреА рд╣реИ:

рдлреНрд░рдВрдЯреЗрдВрдб: рдХрд╛рд░реНрдб рдкреЗрдЬ
рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рдЖрдк рдПрд╕рдПрд╕рдЖрд░ рдХреЗ рд╕рд╛рде рдкреЗрдЬ рдмрдирд╛ рд╕рдХреЗрдВ, рдЖрдкрдХреЛ рдПрд╕рдПрд╕рдЖрд░ рдХреЗ рдмрд┐рдирд╛ рдкреЗрдЬ рдмрдирд╛рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ! рдЪрд▓реЛ рдЕрдВрдд рдореЗрдВ рдХрд╛рд░реНрдб рддрдХ рдкрд╣реБрдВрдЪ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рд╕рд░рд▓ рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдФрд░ рд╕рд╛рдордиреЗ рдХреЗ рдЫреЛрд░ рдкрд░ рдХрд╛рд░реНрдб рдкреЗрдЬ рдмрдирд╛рдПрдВред
рдмреБрджреНрдзрд┐рдорддреНрддрд╛ рдХрд╛ рд▓рд╛рдн рдЙрдард╛рдиреЗ рдФрд░ рд╣рдорд╛рд░реА рд░рд╛рдЬреНрдп рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдирдпрд╛ рд╕реНрд╡рд░реВрдк рджреЗрдиреЗ рдХрд╛ рд╕рдордпред рдЗрд╕ рд╡рд┐рд╖рдп рдкрд░
рдмрд╣реБрдд рд╕рд╛рд░реА рд╕рд╛рдордЧреНрд░рд┐рдпрд╛рдВ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдореЗрд░рд╛ рд╕реБрдЭрд╛рд╡ рд╣реИ рдХрд┐ рдмреБрджреНрдзрд┐рдорддрд╛ рдХрд╛ рджреБрд░реБрдкрдпреЛрдЧ рди рдХрд░реЗрдВ рдФрд░ рд╕рд░рд▓ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬреИрд╕реЗ:
{ "page": { "type": "card", // // type=card: "cardSlug": "...", // "isFetching": false, // API "cardData": {...}, // ( ) // ... }, // ... }
рдЖрдЗрдП "рдХрд╛рд░реНрдб" рдШрдЯрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ, рдЬреЛ рдХрд╛рд░реНрдбрдбреИрдЯ рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдкреНрд░реЙрдкреНрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ (рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдб рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЗ рд░реВрдк рдореЗрдВ рд╣реИ):
рдЕрдм рдЪрд▓реЛ рдХрд╛рд░реНрдб рдХреЗ рд╕рд╛рде рдкреВрд░реЗ рдкреГрд╖реНрда рдХреЗ рд▓рд┐рдП рдПрдХ рдШрдЯрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред рд╡рд╣ рдПрдкреАрдЖрдИ рд╕реЗ рдЖрд╡рд╢реНрдпрдХ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рдЗрд╕реЗ рдХрд╛рд░реНрдб рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдЧрд╛ред рдФрд░ рд╣рдо React-Redux рддрд░реАрдХреЗ рд╕реЗ рдбреЗрдЯрд╛ рд▓рд╛рдиреЗ рдХрд╛ рдХрд╛рдо рдХрд░реЗрдВрдЧреЗред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдлрд╝рд╛рдЗрд▓
frontend/src/redux/actions.js
рдмрдирд╛рдПрдВ рдФрд░ рдПрдХ рдПрдХреНрд╢рди рдмрдирд╛рдПрдВ, рдЬреЛ рдПрдкреАрдЖрдИ рд╕реЗ рдХрд╛рд░реНрдб рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИ, рдпрджрд┐ рдкрд╣рд▓реЗ рд╕реЗ рдирд╣реАрдВ:
export function fetchCardIfNeeded() { return (dispatch, getState) => { let state = getState().page; if (state.cardData === undefined || state.cardData.slug !== state.cardSlug) { return dispatch(fetchCard()); } }; }
fetchCard
рдХреНрд░рд┐рдпрд╛, рдЬреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ
fetchCard
рдмрдирд╛рддреА рд╣реИ, рдереЛрдбрд╝рд╛ рдФрд░ рдЬрдЯрд┐рд▓:
function fetchCard() { return (dispatch, getState) => {
рдУрд╣, рд╣рдореЗрдВ рдПрдХ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдорд┐рд▓реА рд╣реИ рдХрд┐ рдЬреЛ рдХреБрдЫ рдХрд░рддрд╛ рд╣реИ! рдпрд╣ reducer рдореЗрдВ рд╕рдорд░реНрдерд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП:
(рдмрджрд▓рддреЗ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд╕рд╛рде рдХрд┐рд╕реА рд╡рд╕реНрддреБ рдХреЛ рдХреНрд▓реЛрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреНрд░реЗрдВрдбреА рд╕рд┐рдВрдЯреИрдХреНрд╕ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВред)рдЕрдм рдЬрдм рд╕рднреА рддрд░реНрдХ Redux рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ, рддреЛ рдШрдЯрдХ рд╕реНрд╡рдпрдВ рд╣реА CardPage
рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рд╕рд░рд▓ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛:
рд╣рдорд╛рд░реЗ рд░реВрдЯ рдРрдк рдШрдЯрдХ рдореЗрдВ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкреЗрдЬ рдЯрд╛рдЗрдк рдХрд░реЗрдВред
рдФрд░ рдЕрдм, рдПрдХ рдЕрдВрддрд┐рдо рдмрд╛рдд - рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдкреНрд░рд╛рд░рдВрдн рдХрд░рдиреЗ page.type
рдФрд░ page.cardSlug
рдпреВрдЖрд░рдПрд▓ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИредрд▓реЗрдХрд┐рди рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдЕрднреА рднреА рдХрдИ рдЦрдВрдб рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╣рдо рдЕрднреА рдПрдХ рдЙрдЪреНрдЪ-рдЧреБрдгрд╡рддреНрддрд╛ рдХрд╛ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЪрд▓реЛ рдЕрдм рдХреЗ рд▓рд┐рдП рдмреЗрд╡рдХреВрдл рдмрдирд╛рддреЗ рд╣реИрдВред рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдмреЗрд╡рдХреВрдл рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрд╡реЗрджрди рдХреЛ рд╢реБрд░реВ рдХрд░рддреЗ рд╕рдордп рдПрдХ рдирд┐рдпрдорд┐рдд!
рдЕрдм рд╣рдо docker-compose up --build frontend
рдЕрдкрдиреЗ рдХрд╛рд░реНрдб рдХрд╛ рдЖрдирдВрдж рд▓реЗрдиреЗ рдХреЗ рд▓рд┐рдП рдлреНрд░рдВрдЯрдПрдВрдб рдХрд╛ рдкреБрдирд░реНрдирд┐рд░реНрдорд╛рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ helloworld
...
рдЗрд╕рд▓рд┐рдП, рдПрдХ рд╕реЗрдХрдВрдб рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ ... рдФрд░ рд╣рдорд╛рд░реА рд╕рд╛рдордЧреНрд░реА рдХрд╣рд╛рдВ рд╣реИ? рдУрд╣, рд╣рдо рдорд╛рд░реНрдХрдбрд╛рдЙрди рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ рднреВрд▓ рдЧрдП!рдХрд╛рд░реНрдпрдХрд░реНрддрд╛: рдЖрд░рдХреНрдпреВ
рдорд╛рд░реНрдХрд╛рдбрд╛рдЙрди рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ рдФрд░ рд╕рдВрднрд╛рд╡рд┐рдд рдЕрд╕реАрдорд┐рдд рдЖрдХрд╛рд░ рдХреЗ рдХрд╛рд░реНрдб рдХреЗ рд▓рд┐рдП HTML рдЙрддреНрдкрдиреНрди рдХрд░рдирд╛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ "рднрд╛рд░реА" рдХрд╛рд░реНрдп рд╣реИ, рдЬреЛ рдмрджрд▓рд╛рд╡реЛрдВ рдХреЛ рд╕рд╣реЗрдЬрддреЗ рд╕рдордп рдмреИрдХрдПрдВрдб рдкрд░ рд╕реАрдзреЗ рд╣рд▓ рд╣реЛрдиреЗ рдХреЗ рдмрдЬрд╛рдп, рдЖрдорддреМрд░ рдкрд░ рдХрддрд╛рд░рдмрджреНрдз рдФрд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓реА рдорд╢реАрдиреЛрдВ рдкрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрддрд╛ рд╣реИредрдХрд╛рд░реНрдп рдХрддрд╛рд░реЛрдВ рдХреЗ рдХрдИ рдЦреБрд▓реЗ рд╕реНрд░реЛрдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИрдВ; рд╣рдо рд░реЗрдбрд┐рд╕ рдФрд░ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЖрд░рдХреНрдпреВ (рд░реЗрдбрд┐рд╕ рдХреНрдпреВ) рд▓реЗрдВрдЧреЗ , рдЬреЛ рдЕрдЪрд╛рд░ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╣рдореЗрдВ рдЙрдирдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП рд╕реНрдкреЙрдирд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХрд╛ рдЖрдпреЛрдЬрди рдХрд░рддрд╛ рд╣реИредрдореВрд▓реА, рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдФрд░ рд╡рд╛рдпрд░рд┐рдВрдЧ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рд╕рдордп!
рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдмреЙрдпрд▓рд░ рдХреЛрдб рдХрд╛ рдПрдХ рд╕рд╛ред
рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП, рдорд┐рд╕реНрдЯреНрдпреВрди рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ рдФрд░ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦреЗрдВ:
рддрд╛рд░реНрдХрд┐рдХ рд░реВрдк рд╕реЗ: рд╣рдореЗрдВ CardDAO
рдХрд╛рд░реНрдб рдХрд╛ рд╕реНрд░реЛрдд рдХреЛрдб рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рдкрд░рд┐рдгрд╛рдо рдмрдЪрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдмрд╛рд╣рд░реА рднрдВрдбрд╛рд░рдг рд╕реЗ рд╕рдВрдмрдВрдз рд░рдЦрдиреЗ рд╡рд╛рд▓реА рд╡рд╕реНрддреБ рдХреЛ рдЕрдЪрд╛рд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХреНрд░рдордмрджреНрдз рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ - рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдпрд╣ рдХрд╛рд░реНрдп рддреБрд░рдВрдд рдирд╣реАрдВ рд▓рд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдЖрд░рдХреНрдпреВ рджреНрд╡рд╛рд░рд╛ рдкрдВрдХреНрддрд┐рдмрджреНрдз рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдПрдХ рдЕрдЪреНрдЫреЗ рддрд░реАрдХреЗ рд╕реЗ, рд╣рдореЗрдВ Wiring
рдкрдХреНрд╖ рдореЗрдВ рдПрдХ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдмрдирд╛рдиреЗ рдФрд░ рдЗрд╕реЗ рд╣рд░ рддрд░рд╣ рд╕реЗ рдлреЗрдВрдХрдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ ... рдЖрдЗрдП рдЗрд╕реЗ рдХрд░реЗрдВ:
рд╣рдордиреЗ рдЕрдкрдиреА рдиреМрдХрд░рд┐рдпреЛрдВ рдХреА рд╢реНрд░реЗрдгреА рдШреЛрд╖рд┐рдд рдХреА, рд╡рд╛рдпрд░рд┐рдВрдЧ рдХреЛ рд╕рднреА рд╕рдорд╕реНрдпрд╛рдУрдВ рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд kwargs рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдлреЗрдВрдХ рджрд┐рдпрд╛ред (рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрд╣ рд╣рд░ рдмрд╛рд░ рдПрдХ рдирдИ рд╡рд╛рдпрд░рд┐рдВрдЧ рдмрдирд╛рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдХреБрдЫ рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд╛рд░реНрдп рд╢реБрд░реВ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЖрд░рдХреНрдпреВ рдХреЗ рдЕрдВрджрд░ рд╣реЛрдиреЗ рд╡рд╛рд▓реЗ рдХрд╛рдВрдЯреЗ рд╕реЗ рдкрд╣рд▓реЗ рдирд╣реАрдВ рдмрдирд╛рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред) рддрд╛рдХрд┐ рд╣рдорд╛рд░реЗ рд╕рднреА рдХрд╛рд░реНрдп рд╡рд╛рдпрд░рд┐рдВрдЧ рдкрд░ рдирд┐рд░реНрднрд░ рди рд╣реЛрдВ - рдЕрд░реНрдерд╛рдд, рд╣рдорд╛рд░реА рд╕рднреА рд╡рд╕реНрддреБрдУрдВ рдкрд░ - рдЪрд▓реЛ рдЖрдЗрдП рдПрдХ рдРрд╕рд╛ рдбреЗрдХреЛрд░реЗрдЯрд░ рдмрдирд╛рдПрдВ рдЬреЛ рд╡рд╛рдпрд░рд┐рдВрдЧ рд╕реЗ рдХреЗрд╡рд▓ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ:
рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдп рдореЗрдВ рдПрдХ рдбреЗрдХреЛрд░реЗрдЯрд░ рдЬреЛрдбрд╝реЗрдВ рдФрд░ рдЬреАрд╡рди рдХрд╛ рдЖрдирдВрдж рд▓реЗрдВ: import mistune from backend.storage.card import CardDAO from backend.tasks.task import task @task def parse_card_markup(card_dao: CardDAO, card_id: str): card = card_dao.get_by_id(card_id) card.html = _parse_markdown(card.markdown) card_dao.update(card) _parse_markdown = mistune.Markdown(escape=True, hard_wrap=False)
рдЬреАрд╡рди рдХрд╛ рдЖрдирдВрдж рд▓реЗрдВ? рдК, рдореИрдВ рдХрд╣рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛, рд╣рдо рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ: $ docker-compose up worker ... Creating habr-app-demo_worker_1 ... done Attaching to habr-app-demo_worker_1 worker_1 | 17:21:03 RQ worker 'rq:worker:49a25686acc34cdfa322feb88a780f00' started, version 0.13.0 worker_1 | 17:21:03 *** Listening on tasks... worker_1 | 17:21:03 Cleaning registries for queue: tasks
III ... рд╡рд╣ рдХреБрдЫ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ! рдмреЗрд╢рдХ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдордиреЗ рдПрдХ рднреА рдХрд╛рд░реНрдп рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдерд╛!рдЖрдЗрдП рд╣рдорд╛рд░реЗ рдЯреВрд▓ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦреЗрдВ, рдЬреЛ рдПрдХ рдЯреЗрд╕реНрдЯ рдХрд╛рд░реНрдб рдмрдирд╛рддрд╛ рд╣реИ, рддрд╛рдХрд┐ рдпрд╣: рдХ) рдХрд╛рд░реНрдб рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрдирд╛ рд╣реБрдЖ рдирд╣реАрдВ рд╣реИ (рдЬреИрд╕рд╛ рдХрд┐ рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд╣реИ); b) рдорд╛рд░реНрдХрд╛рдбрд╛рдЙрди рдХреЗ рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдкрд░ рдХрд╛рд░реНрдп рдХрд░рдирд╛ред
рдЙрдкрдХрд░рдг рдЕрдм рди рдХреЗрд╡рд▓ рдмреИрдХрдПрдВрдб рдкрд░, рдмрд▓реНрдХрд┐ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдкрд░ рднреА рдЪрд▓рд╛рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рдЕрдм рд╣рдореЗрдВ рдкрд░рд╡рд╛рд╣ рдирд╣реАрдВ рд╣реИред рд╣рдо рдЗрд╕реЗ рд▓реЙрдиреНрдЪ рдХрд░рддреЗ рд╣реИрдВ docker-compose exec worker python -m tools.add_test_content
рдФрд░ рдЯрд░реНрдорд┐рдирд▓ рдХреЗ рдПрдХ рдкрдбрд╝реЛрд╕реА рдЯреИрдм рдореЗрдВ рд╣рдореЗрдВ рдПрдХ рдЪрдорддреНрдХрд╛рд░ рджрд┐рдЦрд╛рдИ рджреЗрддрд╛ рд╣реИ - рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдиреЗ SOMETHING рдХрд┐рдпрд╛! worker_1 | 17:34:26 tasks: backend.tasks.parse.parse_card_markup(card_id='5c715dd1e201ce000c6a89fa') (613b53b1-726b-47a4-9c7b-97cad26da1a5) worker_1 | 17:34:27 tasks: Job OK (613b53b1-726b-47a4-9c7b-97cad26da1a5) worker_1 | 17:34:27 Result is kept for 500 seconds
рдмреИрдХрдПрдВрдб рдХреЗ рд╕рд╛рде рдХрдВрдЯреЗрдирд░ рдХреЗ рдкреБрдирд░реНрдирд┐рд░реНрдорд╛рдг рдХреЗ рдмрд╛рдж, рд╣рдо рдЕрдВрдд рдореЗрдВ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЕрдкрдиреЗ рдХрд╛рд░реНрдб рдХреА рд╕рд╛рдордЧреНрд░реА рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:
рд╕реАрдорд╛рдВрдд рдиреЗрд╡рд┐рдЧреЗрд╢рди
рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо SSR рдкрд░ рдЖрдЧреЗ рдмрдврд╝реЗрдВ, рд╣рдореЗрдВ рдЕрдкрдиреЗ рд╕рднреА React рдЙрдкрджреНрд░рд╡ рдХреЛ рдереЛрдбрд╝рд╛ рд╕рд╛рд░реНрдердХ рдХрд░рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ рдФрд░ рд╣рдорд╛рд░реЗ рдПрдХрд▓ рдкреГрд╖реНрда рдХреЗ рдЖрд╡реЗрджрди рдХреЛ рд╕рд╣реА рдорд╛рдпрдиреЗ рдореЗрдВ рдПрдХ рд╣реА рдкреГрд╖реНрда рдмрдирд╛рдирд╛ рд╣реИред рдЖрдЗрдП рджреЛ (рдПрдХ рдирд╣реАрдВ, рдФрд░ рджреЛ!) рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдЯреВрд▓ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВ, I рдЕрдм рдмрд┐рдЧ рдбреЗрдЯ рдбреЗрд╡рд▓рдкрд░!) рдХрд╛рд░реНрдб рдЬреЛ рдПрдХ рджреВрд╕рд░реЗ рд╕реЗ рд▓рд┐рдВрдХ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рд╣рдо рдЙрдирдХреЗ рдмреАрдЪ рдиреЗрд╡рд┐рдЧреЗрд╢рди рд╕реЗ рдирд┐рдкрдЯреЗрдВрдЧреЗредрдЫрд┐рдкрд╛ рд╣реБрдЖ рдкрд╛рда рдЕрдм рд╣рдо рд▓рд┐рдВрдХ рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЪрд┐рдВрддрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рд░ рдмрд╛рд░ рд╣рдорд╛рд░рд╛ рдЕрджреНрднреБрдд рдЖрд╡реЗрджрди рдХреИрд╕реЗ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕реЗ рд░реЛрдХреЛ!рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд▓рд┐рдВрдХ рдкрд░ рдХреНрд▓рд┐рдХ рдкрд░ рдЕрдкрдирд╛ рд╣реИрдВрдбрд▓рд░ рд▓рдЧрд╛рдПрдВред рдЪреВрдВрдХрд┐ рд▓рд┐рдВрдХ рд╡рд╛рд▓реЗ HTML рдмреИрдХрдПрдВрдб рд╕реЗ рдЖрддреЗ рд╣реИрдВ, рдФрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд░рд┐рдПрдХреНрдЯ рдХреЗ рд╕рд╛рде рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдереЛрдбрд╝рд╛ рд░рд┐рдПрдХреНрдЯ-рд╡рд┐рд╢рд┐рд╖реНрдЯ рдлреЛрдХрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдЪреВрдВрдХрд┐ рд╣рдорд╛рд░реЗ рдШрдЯрдХ рдореЗрдВ рдХрд╛рд░реНрдб рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд╕рд╛рде рд╕рднреА рддрд░реНрдХ CardPage
, рдХрд╛рд░реНрд░рд╡рд╛рдИ рдореЗрдВ рд╣реА (рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ!), рдХреЛрдИ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ: export function navigate(link) { return { type: NAVIGATE, path: link.pathname } }
рдЗрд╕ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдореВрд░реНрдЦ reducer рдЬреЛрдбрд╝реЗрдВ:
рдЪреВрдВрдХрд┐ рдЕрдм рд╣рдорд╛рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдмрджрд▓ рд╕рдХрддреА рд╣реИ, CardPage
рдЗрд╕рд▓рд┐рдП componentDidUpdate
рд╣рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рдЬреЛрдбрд╝реЗ рдЧрдП рддрд░реАрдХреЗ рдХреЗ рд╕рдорд╛рди рдПрдХ рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ componentWillMount
ред рдЕрдм, рдЧреБрдгреЛрдВ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж CardPage
(рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, cardSlug
рдиреЗрд╡рд┐рдЧреЗрд╢рди рдХреЗ рджреМрд░рд╛рди рдЧреБрдг ), рдмреИрдХрдПрдВрдб рд╕реЗ рдХрд╛рд░реНрдб рдХреА рд╕рд╛рдордЧреНрд░реА рдХрд╛ рднреА рдЕрдиреБрд░реЛрдз рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ (рдпрд╣ componentWillMount
рдХреЗрд╡рд▓ рддрдм рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рдЬрдм рдШрдЯрдХ рдЖрд░рдВрднреАрдХреГрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛)редрдареАрдХ рд╣реИ, docker-compose up --build frontend
рдФрд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдиреЗрд╡рд┐рдЧреЗрд╢рди рд╣реИ!
рдПрдХ рдЪреМрдХрд╕ рдкрд╛рдардХ рдпрд╣ рдиреЛрдЯ рдХрд░реЗрдЧрд╛ рдХрд┐ рдХрд╛рд░реНрдб рдХреЗ рдмреАрдЪ рдиреЗрд╡рд┐рдЧреЗрдЯ рдХрд░рддреЗ рд╕рдордп рдкреГрд╖реНрда рдХрд╛ URL рдирд╣реАрдВ рдмрджрд▓реЗрдЧрд╛ - рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рд╕реНрдХреНрд░реАрдирд╢реЙрдЯ рдореЗрдВ рд╣рдо рд╣реИрд▓реЛ, рдбреЗрдореЛ-рдХрд╛рд░реНрдб рдХреЗ рдкрддреЗ рдкрд░ рд╡рд┐рд╢реНрд╡-рдХрд╛рд░реНрдб рджреЗрдЦрддреЗ рд╣реИрдВред рддрджрдиреБрд╕рд╛рд░, рдЖрдЧреЗ-рдкреАрдЫреЗ рдХрд╛ рдиреЗрд╡рд┐рдЧреЗрд╢рди рднреА рдмрдВрдж рд╣реЛ рдЧрдпрд╛ред рдЖрдЗрдП рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрддрд┐рд╣рд╛рд╕ рдХреЗ рд╕рд╛рде рдХреБрдЫ рдХрд╛рд▓рд╛ рдЬрд╛рджреВ рдЬреЛрдбрд╝реЗрдВ!рд╕рдмрд╕реЗ рд╕рд░рд▓ рдмрд╛рдд рдЬреЛ рдЖрдк рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рд╡рд╣ рд╣реИ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдореЗрдВ рдЬреЛрдбрд╝рдирд╛редnavigate
рдПрдХ рдЪреБрдиреМрддреА history.pushState
ред export function navigate(link) { history.pushState(null, "", link.href); return { type: NAVIGATE, path: link.pathname } }
рдЕрдм, рд▓рд┐рдВрдХ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдкрд░, рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЗ рдПрдбреНрд░реЗрд╕ рдмрд╛рд░ рдореЗрдВ URL рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдмрджрд▓ рдЬрд╛рдПрдЧрд╛ред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдмреИрдХ рдмрдЯрди рдЯреВрдЯ рдЬрд╛рдПрдЧрд╛ !рдЗрд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ popstate
рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рдШрдЯрдирд╛ рдХреЛ рд╕реБрдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ window
ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЕрдЧрд░ рдЗрд╕ рдШрдЯрдирд╛ рдореЗрдВ рд╣рдо рдиреЗрд╡рд┐рдЧреЗрд╢рди рдХреЛ рдЖрдЧреЗ рдФрд░ рдкреАрдЫреЗ (рдпрд╛рдиреА рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ dispatch(navigate(...))
) рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ navigate
рдПрдХ рд╡рд┐рд╢реЗрд╖ pushState
" рдбреЛрдВрдЯ " рдлреНрд▓реИрдЧ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ (рдЕрдиреНрдпрдерд╛ рд╕рдм рдХреБрдЫ рдФрд░ рднреА рдЕрдзрд┐рдХ рдЯреВрдЯ рдЬрд╛рдПрдЧрд╛!)ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, "рд╣рдорд╛рд░реЗ" рд░рд╛рдЬреНрдпреЛрдВ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ pushState
рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреЛ рдмрдЪрд╛рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП ред рдмрд╣реБрдд рд╕рд╛рд░рд╛ рдЬрд╛рджреВ рдФрд░ рдбрд┐рдмрдЧ рд╣реИ, рддреЛ рдЪрд▓реЛ рдХреЛрдб рдХреЛ рд╕рд╣реА рдХрд░реЗрдВ! рдпрд╣рд╛рдВ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдРрдк рдХреИрд╕рд╛ рджрд┐рдЦреЗрдЧрд╛:
рдФрд░ рдпрд╣рд╛рдБ рдиреЗрд╡рд┐рдЧреЗрдЯ рдХрд╛рд░реНрд░рд╡рд╛рдИ рд╣реИ:
рдЕрдм рдХрд╣рд╛рдиреА рдХрд╛рдо рдХрд░реЗрдЧреАредрдЦреИрд░, рдЕрдВрддрд┐рдо рд╕реНрдкрд░реНрд╢: рдЪреВрдВрдХрд┐ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдХрд╛рд░реНрд░рд╡рд╛рдИ рд╣реИ navigate
, рдЗрд╕рд▓рд┐рдП рд╣рдо рдЙрд╕ рдХреНрд▓рд╛рдЗрдВрдЯ рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдХреЛрдб рдХреНрдпреЛрдВ рдирд╣реАрдВ рдЫреЛрдбрд╝рддреЗ рд╣реИрдВ рдЬреЛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╕реНрдерд┐рддрд┐ рдХреА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИ? рд╣рдо рд╡рд░реНрддрдорд╛рди рд╕реНрдерд╛рди рдкрд░ рдиреЗрд╡рд┐рдЧреЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
рдХреЙрдкреА-рдкреЗрд╕реНрдЯ рдирд╖реНрдЯ!рдлрд╝реНрд░рдВрдЯреЗрдВрдб: рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рд░реЗрдВрдбрд░рд┐рдВрдЧ
рдпрд╣ рд╣рдорд╛рд░реЗ рдореБрдЦреНрдп (рдореЗрд░реА рд░рд╛рдп рдореЗрдВ) рдЪрд┐рдкреНрд╕ рдХреЗ рд▓рд┐рдП рд╕рдордп рд╣реИ - рдПрд╕рдИрдУ-рдорд┐рддреНрд░рддрд╛ред рддрд╛рдХрд┐ рдЦреЛрдЬ рдЗрдВрдЬрди рд╣рдорд╛рд░реА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдЕрдиреБрдХреНрд░рдордгрд┐рдд рдХрд░ рд╕рдХреЗрдВ, рдЬреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рдШрдЯрдХреЛрдВ рдореЗрдВ рдмрдирд╛рдИ рдЧрдИ рд╣реИ, рд╣рдореЗрдВ рдЙрдиреНрд╣реЗрдВ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рджреЗрдиреЗ рдХреЗ рдкрд░рд┐рдгрд╛рдо рджреЗрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдпрд╣ рднреА рд╕реАрдЦреЗрдВ рдХрд┐ рдЗрд╕ рдкрд░рд┐рдгрд╛рдо рдХреЛ рдлрд┐рд░ рд╕реЗ рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдПредрд╕рд╛рдорд╛рдиреНрдп рдпреЛрдЬрдирд╛ рд╕рд░рд▓ рд╣реИред рдкрд╣рд▓рд╛: рд╣рдореЗрдВ рдЕрдкрдиреЗ рд░рд┐рдПрдХреНрдЯ рдШрдЯрдХ рджреНрд╡рд╛рд░рд╛ рдЙрддреНрдкрдиреНрди HTML рдХреЛ рд╣рдорд╛рд░реЗ HTML рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ App
ред рдпрд╣ HTML рд╕рд░реНрдЪ рдЗрдВрдЬрди (рдФрд░ рдЬреЗрдПрд╕ рдмрдВрдж рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЗ рд╕рд╛рде, рд╣реЗрд╣реЗ) рджреНрд╡рд╛рд░рд╛ рджреЗрдЦрд╛ рдЬрд╛рдПрдЧрд╛ред рджреВрд╕рд░рд╛: рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рдПрдХ рдЯреИрдЧ рдЬреЛрдбрд╝реЗрдВ рдЬреЛ <script>
рдХрд╣реАрдВ рдмрдЪрд╛рддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ window
) рдПрдХ рд░рд╛рдЬреНрдп рдбрдВрдк рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рдпрд╣ HTML рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдлрд┐рд░ рд╣рдо рддреБрд░рдВрдд рдЗрд╕ рд░рд╛рдЬреНрдп рдХреЗ рд╕рд╛рде рдЧреНрд░рд╛рд╣рдХ рдкрдХреНрд╖ рдкрд░ рдЕрдкрдиреЗ рдЖрд╡реЗрджрди рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рджрд┐рдЦрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рдЬрд░реВрд░рдд рд╣реИ (рд╣рдо рд╣рд╛рдЗрдбреНрд░реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рднреА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВрдЬрдирд░реЗрдЯ рдХрд┐рдП рдЧрдП HTML рдореЗрдВ, рддрд╛рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ DOM рдЯреНрд░реА рдХреЛ рдлрд┐рд░ рд╕реЗ рди рдмрдирд╛рдпрд╛ рдЬрд╛рдП)редрдЖрдЗрдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрдХрд░ рд╢реБрд░реВ рдХрд░реЗрдВ рдЬреЛ HTML рдФрд░ рдЕрдВрддрд┐рдо рд╕реНрдерд┐рддрд┐ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред
рд╣рдорд╛рд░реЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рдирдП рддрд░реНрдХ рдФрд░ рддрд░реНрдХ рдЬреЛрдбрд╝реЗрдВ, рдЬрд┐рдирдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣рдордиреЗ рдКрдкрд░ рдмрддрд╛рдпрд╛ рд╣реИ:
рд╣рдорд╛рд░рд╛ рдПрдХреНрд╕рдкреНрд░реЗрд╕ рд╕рд░реНрд╡рд░ рдереЛрдбрд╝рд╛ рдФрд░ рдЬрдЯрд┐рд▓ рд╣реЛ рдЧрдпрд╛ рд╣реИ:
рд▓реЗрдХрд┐рди рдЧреНрд░рд╛рд╣рдХ рдЖрд╕рд╛рди рд╣реИ:
рдЕрдЧрд▓рд╛, рдЖрдкрдХреЛ "рдЗрддрд┐рд╣рд╛рд╕ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдирд╣реАрдВ рд╣реИ" рдЬреИрд╕реЗ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рд╕рд╛рдл рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рд╕рд░рд▓ (рдЕрдм рддрдХ) рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХрд╣реАрдВ рдкрд░ рдЬреЛрдбрд╝реЗрдВ utility.js
ред
рдлрд┐рд░ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рджрд┐рдирдЪрд░реНрдпрд╛ рдореЗрдВ рдмрджрд▓рд╛рд╡ рд╣реЛрдВрдЧреЗ рдЬреЛ рдореИрдВ рдпрд╣рд╛рдВ рдирд╣реАрдВ рд▓рд╛рдКрдВрдЧрд╛ (рд▓реЗрдХрд┐рди рдЙрдиреНрд╣реЗрдВ рдЗрд╕рдХреЗ рдЕрдиреБрд░реВрдк рдкреНрд░рддрд┐рдмрджреНрдз рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ )ред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣рдорд╛рд░рд╛ рд░рд┐рдПрдХреНрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдФрд░ рд╕рд░реНрд╡рд░ рджреЛрдиреЛрдВ рдореЗрдВ рд░реЗрдВрдбрд░ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдЧрд╛редрдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ!
рд▓реЗрдХрд┐рди рд╡рд╣рд╛рдБ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ рд╡реЗ рдХрд╣рддреЗ рд╣реИрдВ, рдПрдХ рдЪреЗрддрд╛рд╡рдиреА ...
рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ? рдореЗрд░реА рд╕реБрдкрд░-рдХреВрд▓ рдлреИрд╢рди рд╕реЗрд╡рд╛ рдкрд░ Google рдЬреЛ рджреЗрдЦ рд░рд╣рд╛ рд╣реИ рд╡рд╣ рд╕рднреА LO LOING рд╣реИредрдЦреИрд░, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рд╕рднреА рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХрддрд╛ рд╣рдорд╛рд░реЗ рдЦрд┐рд▓рд╛рдл рдЦреЗрд▓реЗ рд╣реИрдВред рдЕрдм рд╣рдореЗрдВ рд╕рд░реНрд╡рд░ рдХреЛ рдпрд╣ рд╕рдордЭрдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдХрд╛рд░реНрдб рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде рдмреИрдХрдПрдВрдб рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рд░реЗрдВрдбрд░ рдХрд░рдиреЗ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рднреЗрдЬрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЗрдВрддрдЬрд╛рд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдФрд░ рдпрд╣ рд╡рд╛рдВрдЫрдиреАрдп рд╣реИ рдХрд┐ рдпрд╣ рд╡рд┐рдзрд┐ рдХрд╛рдлреА рд╕рд╛рдорд╛рдиреНрдп рд╣реЛредрдХрдИ рд╕рдорд╛рдзрд╛рди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рдПрдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдПрдХ рдЕрд▓рдЧ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╡рд░реНрдгрди рдХрд░рдирд╛ рд╣реИ рдХрд┐ рдХрд┐рд╕ рдкрде рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░ рдЖрд╡реЗрджрди ( рд▓реЗрдЦ ) рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдРрд╕рд╛ рдХрд░реЗрдВ ред рдЗрд╕ рдШреЛрд▓ рдХреЗ рдХрдИ рдлрд╛рдпрджреЗ рд╣реИрдВред рдпрд╣ рд╕рд░рд▓ рд╣реИ, рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реИ, рдФрд░ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИредрдПрдХ рдкреНрд░рдпреЛрдЧ рдХреЗ рд░реВрдк рдореЗрдВ (рдореВрд▓ рд╕рд╛рдордЧреНрд░реА рдХрдо рд╕реЗ рдХрдо рдХрд╣реАрдВ рд▓реЗрдЦ рдореЗрдВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП!) рдореИрдВ рдПрдХ рдФрд░ рдпреЛрдЬрдирд╛ рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рдХрд░рддрд╛ рд╣реВрдВред рд╣рд░ рдмрд╛рд░ рдЬрдм рд╣рдо рдХреБрдЫ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЪрд▓рд╛рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рд╣рдореЗрдВ рдЗрдВрддрдЬрд╛рд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рддреЛ рдЙрдкрдпреБрдХреНрдд рд╡рд╛рджрд╛ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬреЛ рд╡рд╛рдкрд╕ рд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ) рдХреЛ рд╣рдорд╛рд░реЗ рд░рд╛рдЬреНрдп рдореЗрдВ рдХрд╣реАрдВ рди рдХрд╣реАрдВ рдЬреЛрдбрд╝реЗрдВред рдЗрд╕рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдЬрдЧрд╣ рд╣реЛрдЧреА рдЬрд╣рд╛рдВ рдЖрдк рд╣рдореЗрд╢рд╛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рд╕рдм рдХреБрдЫ рдбрд╛рдЙрдирд▓реЛрдб рд╣реЛ рдЪреБрдХрд╛ рд╣реИредрджреЛ рдирдИ рдХреНрд░рд┐рдпрд╛рдПрдВ рдЬреЛрдбрд╝реЗрдВред
рдЬрдм рднреНрд░реВрдг рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдкрд╣рд▓реЗ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рджреВрд╕рд░рд╛ - рдЗрд╕рдХреЗ рдЕрдВрдд рдореЗрдВ .then()
редрдЕрдм рдЙрдирдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ reducer рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:
рдЕрдм рд╣рдо рдХрд╛рд░реНрд░рд╡рд╛рдИ рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░реЗрдВрдЧреЗ fetchCard
:
рдпрд╣ initialState
рдЦрд╛рд▓реА рд╕рд░рдгреА рдореЗрдВ рд╡рд╛рджреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдФрд░ рд╕рд░реНрд╡рд░ рдХреЛ рдЙрди рд╕рднреА рдХреЗ рд▓рд┐рдП рдЗрдВрддрдЬрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ ! рд░реЗрдВрдбрд░ рдлрд╝рдВрдХреНрд╢рди рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдирд┐рдореНрди рд░реВрдк рд▓реЗрддрд╛ рд╣реИ:
рдЕрдзрд┐рдЧреНрд░рд╣реАрдд render
рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХрддрд╛ рдХреЗ рдХрд╛рд░рдг , рдЕрдиреБрд░реЛрдз рд╣реИрдВрдбрд▓рд░ рднреА рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реИ:
Et voil├а!
рдирд┐рд╖реНрдХрд░реНрд╖
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рд╛рдИ-рдЯреЗрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдирд╛ рдЗрддрдирд╛ рд╕рд░рд▓ рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди рдЗрддрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ! рдЕрдВрддрд┐рдо рдЖрд╡реЗрджрди рдЧрд┐рддреБрдм рдкрд░ рднрдВрдбрд╛рд░ рдореЗрдВ рд╣реИ рдФрд░, рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рд░реВрдк рд╕реЗ, рдЖрдкрдХреЛ рдЗрд╕реЗ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рдбреЙрдХрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИредрдпрджрд┐ рд▓реЗрдЦ рдорд╛рдВрдЧ рдореЗрдВ рд╣реИ, рддреЛ рдЗрд╕ рднрдВрдбрд╛рд░ рдХреЛ рднреА рдирд╣реАрдВ рдЫреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛! рд╣рдо рдЗрд╕реЗ рдЕрдиреНрдп рдЬреНрдЮрд╛рди рд╕реЗ рдХреБрдЫ рдХреЗ рд╕рд╛рде рджреЗрдЦ рдкрд╛рдПрдВрдЧреЗ рдЬреЛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ:- рд▓реЙрдЧрд┐рдВрдЧ, рдирд┐рдЧрд░рд╛рдиреА, тАЛтАЛрд▓реЛрдб рдкрд░реАрдХреНрд╖рдгред
- рдкрд░реАрдХреНрд╖рдг, рд╕реАрдЖрдИ, рд╕реАрдбреАред
- рдХреВрд▓рд░ рдореЗрдВ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдпрд╛ рдкреВрд░реНрдг-рдкрд╛рда рдЦреЛрдЬ рдЬреИрд╕реА рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рд╣реИрдВред
- рдЙрддреНрдкрд╛рджрди рд╡рд╛рддрд╛рд╡рд░рдг рдХрд╛ рд╕реЗрдЯрдЕрдк рдФрд░ рд╡рд┐рдХрд╛рд╕ред
рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!