[React] 6. Handling Events

Binding render ( ) { return ( < button onClick = { this . handleClick } > { this . state . isToggleOn ? 'ON' : 'OFF' } </ button > ) ; } 위처럼 ()를 붙이지 않고 method를 레퍼런스하는 경우, 메서드를 바인드 해주어야 한다. constructor ( props ) { super ( props ) ; this . state = { isToggleOn : true } ; // This binding is necessary to make `this` work in the callback this . handleClick = this . handleClick . bind ( this ) ; } 이렇게 매번 바인딩해줘야 하는 것이 불편하다면, class LoggingButton extends React . Component { // This syntax ensures `this` is bound within handleClick. // Warning: this is *experimental* syntax. handleClick = ( ) => { console . log ( 'this is:' , this ) ; } render ( ) { return ( < button onClick = { this . handleClick } > Click me </ button > ) ; } } 이렇게 Arrow Function을 사용할 수 있다.

[React] 4. Components and Props

Javascript Function style component function Welcome ( props ) { return < h1 > Hello, { props . name } </ h1 > ; } ES6 class style component class Welcome extends React . Component { render ( ) { return < h1 > Hello, { this . props . name } </ h1 > ; } } render ReactDOM . render ( element , document . getElementById ( 'root' ) ) ; 요렇게 하면 element를 root라는 element 하위로 render하겠다는 것이다. User-defined Component React는 user-defined component를 사용하는 element를 만나면 해당 element의 attribute을 props에 넣어 user-defined component로 전달한다. 그리고 중요한 점은 component의 이름을 지을때 항상 대문자로 시작하도록 해야한다. 소문자로 시작하면 React는 해당 component를 DOM tag로 취급한다. Components should not attempt to modify props!

[React] Tic Tac Toe 과거기록에서 이어서 하기 / Resume from history

React 튜토리얼에서 Tic Tac Toe가 진행되는 과정을 히스토리로 저장하고 돌아갈 수 있는데 이어서 할 수는 없습니다. 이를 보완한 코드입니다. ------------------------------------------- function Square(props) {   return (     <button className="square" onClick={props.onClick}>       {props.value}     </button>   ); } function calculateWinner(squares) {   const lines = [     [0, 1, 2],     [3, 4, 5],     [6, 7, 8],     [0, 3, 6],     [1, 4, 7],     [2, 5, 8],     [0, 4, 8],     [2, 4, 6],   ];   for (let i = 0; i < lines.length; i++) {     const [a, b, c] = lines[i];     if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {       return squares[a];     }   }   return null; } class Board extends React.Component {   renderSquare(i) {     return (   ...

Django Channels - Consumers

Consumer하는 일 중 몇가지:     - 이벤트가 발생했을 때 사용할 함수를 작성하기만 하면 된다. event loop전체를 다 쓸 필요가 없다.     - synchronous / asynchronous 코드를 작성하기만 하면 threading을 포함한 나머지를 다 처리해준다. Consumer Events from channels.consumer import SyncConsumer class EchoConsumer ( SyncConsumer ): def websocket_connect ( self , event ): self . send ({ "type" : "websocket.accept" , }) def websocket_receive ( self , event ): self . send ({ "type" : "websocket.send" , "text" : event [ "text" ], }) Consumer는 type과 매칭되는 몇가지의 메소드들로 구성되어 있다. type에서 .를 _로 바꾼것이 메소드 이름이다. 즉 위의 예시에서 "type": "websocket.accpet" 는 websocket_accept()를 호출하고 "type": "websocket.send"는 websocket_send()를 호출한다. 그렇다면 위의 예시에서 websocket_receive(self, event)는 event["text"]를 접근하고 있는데 websocket_receive의 event안에 text가 있다는 것은 어떻게 알았을까? 이는 ASGI...

Django Channels - Introduction

Scope란 connection의 정보를 뜻한다. remote IP, username, lifetime of connection등의 정보를 가지고 있다. Application은 한번의 scope당 한번씩 instantiate된다. HTTP에서는 각 request마다, socket에서는 각 WebSocket connection마다이다. Consumer 각각의 프로토콜은 각자 다른 event들이 발생하며 이 event들은 메소드로 표현된다. 개발자는 각각의 event들을 어떻게 처리할지 코드만 작성하면 Django의 Channel이 스케쥴링과 병렬적으로 실행시켜준다. class LogConsumer ( WebsocketConsumer ): def connect ( self , message ): Log . objects . create ( type = "connected" , client = self . scope [ "client" ], ) Channel은 asynchronous event loop을 기반으로 돌아간다.  하지만 위처럼 코드를 작성하면 synchronous thread에서 실행이 된다. 따라서 위의 코드처럼 blocking operation도 문제없이 잘 작동한다. class PingConsumer ( AsyncConsumer ): async def websocket_connect ( self , message ): await self . send ({ "type" : "websocket.accept" , }) async def websocket_receive ( self , message ): await asyncio . sleep ( 1 ) ...

[Django REST Framework] create() vs perform_create()

Django REST Framework의 ModelViewSet과 create() 관련 찾아보고 공부한 내용을 정리해보려고 한다. 기본적으로 ModelViewSet은 GenericAPIView라는 클래스를 상속받기 때문에 .list(), .create()  .list(), .create() 등을 기본으로 내장하고 있다. 따라서 이 중에서 기본 내장되어 있는 메소드 중 동작을 변경하고 싶은 것들만 overriding해서 수정하면 된다. 그리고 ModelViewSet은 GenericAPIView를 상속받고 있기 때문에 최소한 queryset와 serializer_class는 세팅해주어야 한다. from rest_framework import status from rest_framework.response import Response def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer): serializer.save() 위의 코드를 보면 이해가 조금 더 쉬울 것 같다. perform_create()은 create()의 동작 중 일부분을 overriding한다고 생각하면 되는데, serializer.save()가 호출될 때 perform_create()가 호출된다고 생각하면 된다. 위의 경우 명시적으로 perform_create()를 호출했지...

[Django 공식문서 번역] REST Framework - Viewset and Router

Viewset을 사용하면 관련된 view들을 하나의 클래스로 묶을 수 있다. class UserViewSet ( viewsets . ViewSet ): """ A simple ViewSet for listing or retrieving users. """ def list ( self , request ): queryset = User . objects . all () serializer = UserSerializer ( queryset , many = True ) return Response ( serializer . data ) def retrieve ( self , request , pk = None ): queryset = User . objects . all () user = get_object_or_404 ( queryset , pk = pk ) serializer = UserSerializer ( user ) return Response ( serializer . data ) from rest_framework import routers router = routers . SimpleRouter () router . register ( r 'users' , UserViewSet ) router . register ( r 'accounts' , AccountViewSet ) urlpatterns = router . urls 위의 예시는 아래의 URL 패턴을 만든다 URL pattern:  ^users/$  Name:  'user-list' URL pattern:  ^users/{pk}/$  Name:  'user-detail' URL...