React stateless 구성 요소에서 이벤트 핸들러를 만드는 최적의 방법을 찾으려고합니다. 다음과 같이 할 수 있습니다.
const myComponent = (props) => {
const myHandler = (e) => props.dispatch(something());
return (
<button onClick={myHandler}>Click Me</button>
);
}
여기서 단점은이 컴포넌트가 렌더링 될 때마다 새로운 “myHandler”함수가 생성된다는 것입니다. 구성 요소 속성에 계속 액세스 할 수있는 상태 비 저장 구성 요소에서 이벤트 처리기를 만드는 더 좋은 방법이 있습니까?
답변
함수 구성 요소의 요소에 핸들러를 적용하는 것은 일반적으로 다음과 같아야합니다.
const f = props => <button onClick={props.onClick}></button>
훨씬 더 복잡한 작업을 수행해야하는 경우 a) 구성 요소가 상태 비 저장 (클래스 또는 후크 사용)이 아니어야하거나 b) 외부 상태 저장 컨테이너 구성 요소에 핸들러를 생성해야한다는 신호입니다.
제쳐두고, 내 첫 번째 요점을 약간 훼손하는 것으로, 구성 요소가 앱의 특히 집중적으로 다시 렌더링되는 부분에 있지 않는 한 .NET에서 화살표 함수를 만드는 것에 대해 걱정할 필요가 없습니다 render()
.
답변
새로운 React hooks 기능을 사용하면 다음과 같이 보일 수 있습니다.
const HelloWorld = ({ dispatch }) => {
const handleClick = useCallback(() => {
dispatch(something())
})
return <button onClick={handleClick} />
}
useCallback
메모 함수를 생성합니다. 즉, 각 렌더링주기에서 새 함수가 재생성되지 않습니다.
https://reactjs.org/docs/hooks-reference.html#usecallback
그러나 이것은 아직 제안 단계에 있습니다.
답변
이 방법은 어떻습니까?
const myHandler = (e,props) => props.dispatch(something());
const myComponent = (props) => {
return (
<button onClick={(e) => myHandler(e,props)}>Click Me</button>
);
}
답변
처리기가 변경되는 속성에 의존하는 경우 캐시 할 상태 저장 인스턴스가 없기 때문에 처리기를 매번 만들어야합니다. 작동 할 수있는 또 다른 대안은 입력 소품을 기반으로 핸들러를 메모하는 것입니다.
몇 가지 구현 옵션
lodash._memoize
R.memoize
fast-memoize
답변
해결책 하나의 mapPropsToHandler 및 event.target.
함수는 js의 객체이므로 속성을 연결할 수 있습니다.
function onChange() { console.log(onChange.list) }
function Input(props) {
onChange.list = props.list;
return <input onChange={onChange}/>
}
이 함수는 속성을 함수에 한 번만 바인딩합니다.
export function mapPropsToHandler(handler, props) {
for (let property in props) {
if (props.hasOwnProperty(property)) {
if(!handler.hasOwnProperty(property)) {
handler[property] = props[property];
}
}
}
}
나는 이렇게 내 소품을 얻습니다.
export function InputCell({query_name, search, loader}) {
mapPropsToHandler(onChange, {list, query_name, search, loader});
return (
<input onChange={onChange}/>
);
}
function onChange() {
let {query_name, search, loader} = onChange;
console.log(search)
}
이 예제는 event.target과 mapPropsToHandler를 모두 결합했습니다. 숫자 나 문자열이 아닌 핸들러에만 함수를 첨부하는 것이 좋습니다. 숫자와 문자열은 다음과 같은 DOM 속성의 도움으로 전달 될 수 있습니다.
<select data-id={id}/>
mapPropsToHandler보다는
import React, {PropTypes} from "react";
import swagger from "../../../swagger/index";
import {sync} from "../../../functions/sync";
import {getToken} from "../../../redux/helpers";
import {mapPropsToHandler} from "../../../functions/mapPropsToHandler";
function edit(event) {
let {translator} = edit;
const id = event.target.attributes.getNamedItem('data-id').value;
sync(function*() {
yield (new swagger.BillingApi())
.billingListStatusIdPut(id, getToken(), {
payloadData: {"admin_status": translator(event.target.value)}
});
});
}
export default function ChangeBillingStatus({translator, status, id}) {
mapPropsToHandler(edit, {translator});
return (
<select key={Math.random()} className="form-control input-sm" name="status" defaultValue={status}
onChange={edit} data-id={id}>
<option data-tokens="accepted" value="accepted">{translator('accepted')}</option>
<option data-tokens="pending" value="pending">{translator('pending')}</option>
<option data-tokens="rejected" value="rejected">{translator('rejected')}</option>
</select>
)
}
솔루션 2입니다. 이벤트 위임
솔루션 1을 참조하십시오. 입력에서 이벤트 핸들러를 제거하고 다른 입력도 보유하는 상위에 놓을 수 있으며 도움말 위임 기술을 통해 event.traget 및 mapPropsToHandler 함수를 다시 사용할 수 있습니다.
답변
다음은 typescript에서 react 및 redux 작성으로 구현 된 내가 가장 좋아하는 제품 목록입니다. 커스텀 핸들러에서 필요한 모든 인수를 전달하고 EventHandler
원본 이벤트 인수를 허용 하는 new 를 반환 할 수 있습니다 . 이것의MouseEvent
예에서.
격리 된 함수는 jsx를 더 깔끔하게 유지하고 여러 linting 규칙을 위반하지 않도록합니다. 이와 같이 jsx-no-bind
, jsx-no-lambda
.
import * as React from 'react';
import { DispatchProp, Dispatch, connect } from 'react-redux';
import { removeFavorite } from './../../actions/favorite';
interface ListItemProps {
prod: Product;
handleRemoveFavoriteClick: React.EventHandler<React.MouseEvent<HTMLButtonElement>>;
}
const ListItem: React.StatelessComponent<ListItemProps> = (props) => {
const {
prod,
handleRemoveFavoriteClick
} = props;
return (
<li>
<a href={prod.url} target="_blank">
{prod.title}
</a>
<button type="button" onClick={handleRemoveFavoriteClick}>×</button>
</li>
);
};
const handleRemoveFavoriteClick = (prod: Product, dispatch: Dispatch<any>) =>
(e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
dispatch(removeFavorite(prod));
};
interface FavoriteListProps {
prods: Product[];
}
const FavoriteList: React.StatelessComponent<FavoriteListProps & DispatchProp<any>> = (props) => {
const {
prods,
dispatch
} = props;
return (
<ul>
{prods.map((prod, index) => <ListItem prod={prod} key={index} handleRemoveFavoriteClick={handleRemoveFavoriteClick(prod, dispatch)} />)}
</ul>
);
};
export default connect()(FavoriteList);
typescript에 익숙하지 않은 경우 다음은 javascript 스 니펫입니다.
import * as React from 'react';
import { DispatchProp, Dispatch, connect } from 'react-redux';
import { removeFavorite } from './../../actions/favorite';
const ListItem = (props) => {
const {
prod,
handleRemoveFavoriteClick
} = props;
return (
<li>
<a href={prod.url} target="_blank">
{prod.title}
</a>
<button type="button" onClick={handleRemoveFavoriteClick}>×</button>
</li>
);
};
const handleRemoveFavoriteClick = (prod, dispatch) =>
(e) => {
e.preventDefault();
dispatch(removeFavorite(prod));
};
const FavoriteList = (props) => {
const {
prods,
dispatch
} = props;
return (
<ul>
{prods.map((prod, index) => <ListItem prod={prod} key={index} handleRemoveFavoriteClick={handleRemoveFavoriteClick(prod, dispatch)} />)}
</ul>
);
};
export default connect()(FavoriteList);
답변
상태 비 저장 구성 요소와 마찬가지로 함수를 추가하면됩니다.
function addName(){
console.log("name is added")
}
반환에서 다음과 같이 호출됩니다. onChange={addName}