편집 : ES6 업데이트 된 예제의 최종 예제를 참조하십시오.
이 답변은 단순히 직접적인 부모-자식 관계의 경우를 처리합니다. 부모와 자녀가 잠재적으로 중개인이 많을 경우이 답변을 확인하십시오 .
다른 솔루션에는 요점이 없습니다
그들은 여전히 잘 작동하지만 다른 답변에는 매우 중요한 것이 빠져 있습니다.
React.js에서 이벤트를 사용하여 자녀의 소품을 부모에게 전달하는 간단한 방법이 있습니까?
부모님은 이미 그 자식 소품을 가지고 있습니다! : 아이가 소품을 가지고 있다면, 그것은 부모가 아이에게 소품을 제공했기 때문입니다! 부모가 이미 그 소도구를 가지고있는 동안 왜 자녀가 소도구를 부모에게 전달하길 원합니까?
더 나은 구현
어린이 : 실제로 그보다 더 복잡 할 필요는 없습니다.
var Child = React.createClass({
render: function () {
return <button onClick={this.props.onClick}>{this.props.text}</button>;
},
});
자녀가있는 부모 : 자녀 에게 전달되는 가치 사용
var Parent = React.createClass({
getInitialState: function() {
return {childText: "Click me! (parent prop)"};
},
render: function () {
return (
<Child onClick={this.handleChildClick} text={this.state.childText}/>
);
},
handleChildClick: function(event) {
// You can access the prop you pass to the children
// because you already have it!
// Here you have it in state but it could also be
// in props, coming from another parent.
alert("The Child button text is: " + this.state.childText);
// You can also access the target of the click here
// if you want to do some magic stuff
alert("The Child HTML is: " + event.target.outerHTML);
}
});
JS 피들
자녀 목록이있는 부모 : 부모에게 필요한 모든 것을 여전히 가지고 있으며 자녀를 더 복잡하게 만들 필요가 없습니다.
var Parent = React.createClass({
getInitialState: function() {
return {childrenData: [
{childText: "Click me 1!", childNumber: 1},
{childText: "Click me 2!", childNumber: 2}
]};
},
render: function () {
var children = this.state.childrenData.map(function(childData,childIndex) {
return <Child onClick={this.handleChildClick.bind(null,childData)} text={childData.childText}/>;
}.bind(this));
return <div>{children}</div>;
},
handleChildClick: function(childData,event) {
alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
alert("The Child HTML is: " + event.target.outerHTML);
}
});
JS 피들
사용 this.handleChildClick.bind(null,childIndex)
후 사용 가능this.state.childrenData[childIndex]
null
그렇지 않으면 React가 자동 바인딩 시스템 과 관련된 경고를 발행하기 때문에 컨텍스트 와 바인딩 합니다. null을 사용하면 함수 컨텍스트를 변경하지 않으려는 것입니다. 도 참조하십시오 .
다른 답변의 캡슐화 및 연결 정보
이것은 나에게 커플 링과 캡슐화 측면에서 나쁜 생각입니다.
var Parent = React.createClass({
handleClick: function(childComponent) {
// using childComponent.props
// using childComponent.refs.button
// or anything else using childComponent
},
render: function() {
<Child onClick={this.handleClick} />
}
});
소품 사용 : 위에서 설명한 것처럼 이미 부모에 소품이 있으므로 전체 자식 구성 요소를 전달하여 소품에 액세스하는 것은 쓸모가 없습니다.
심판 사용 : 이벤트에 이미 클릭 타겟이 있으며 대부분의 경우 충분합니다. 또한 자녀에게 직접 심판을 사용할 수 있습니다.
<Child ref="theChild" .../>
그리고 부모의 DOM 노드에 액세스하십시오.
React.findDOMNode(this.refs.theChild)
부모에서 자식의 여러 참조에 액세스하려는 고급 경우 자식은 콜백에서 직접 모든 DOM 노드를 전달할 수 있습니다.
컴포넌트에는 인터페이스 (props)가 있으며 부모는 내부 DOM 구조 또는 참조를 선언하는 DOM 노드를 포함하여 자식의 내부 작업에 대해 아무 것도 가정해서는 안됩니다. 자녀의 심판을 사용하는 부모는 두 구성 요소를 단단히 결합한다는 것을 의미합니다.
이 문제를 설명하기 위해 브라우저 내에서 슬라이더, 스크롤 막대, 비디오 플레이어와 같은 것을 렌더링하는 데 사용되는 Shadow DOM 에 대해이 인용문을 가져옵니다 .
이들은 웹 개발자가 도달 할 수있는 것과 구현 세부 사항으로 간주되는 것 사이에 경계를 만들었으므로 액세스 할 수 없습니다. 그러나 브라우저는이 경계를 자유롭게 통과 할 수 있습니다. 이러한 경계가 정해지면, 그들은 div와 범위에서 같은 오래된 웹 기술을 사용하여 모든 HTML 요소를 원하는대로 구축 할 수있었습니다.
문제는 자식 구현 세부 정보가 부모에게 유출되도록하면 부모에게 영향을 미치지 않고 자식을 리팩터링하는 것이 매우 어렵다는 것입니다. 이것은 라이브러리 작성자 (또는 Shadow DOM을 사용하는 브라우저 편집기)로서 클라이언트가 너무 많은 액세스를 허용하여 역 호환성을 해치지 않고 코드를 업그레이드하기가 매우 어렵 기 때문에 매우 위험하다는 것을 의미합니다.
Chrome에서 클라이언트가 해당 스크롤 막대의 내부 dom 노드에 액세스 할 수 있도록 스크롤 막대를 구현 한 경우 클라이언트가 해당 스크롤 막대를 간단하게 중단 할 수 있으며 Chrome에서 리팩터링 후 자동 업데이트를 수행하면 앱이 더 쉽게 중단 될 수 있습니다. scrollbar ... 대신 CSS를 사용하여 스크롤 막대의 일부를 사용자 정의하는 것과 같은 안전한 것들에만 액세스 할 수 있습니다.
다른 것을 사용하는 것에 대하여
콜백에서 전체 구성 요소를 전달하는 것은 위험하며 초보자 개발자가 부모 내부에서 또는를 호출 childComponent.setState(...)
하거나 childComponent.forceUpdate()
새 변수를 부모 내부에 할당하는 것과 같은 매우 이상한 일을 수행 하여 전체 앱을 추론하기가 훨씬 더 어려워 질 수 있습니다.
편집 : ES6 예제
많은 사람들이 이제 ES6을 사용함에 따라 ES6 구문과 동일한 예가 있습니다.
아이는 매우 간단 할 수 있습니다.
const Child = ({
onClick,
text
}) => (
<button onClick={onClick}>
{text}
</button>
)
부모는 클래스가 될 수 있습니다 (그리고 결국 상태 자체를 관리 할 수는 있지만 여기에 소품으로 전달합니다.
class Parent1 extends React.Component {
handleChildClick(childData,event) {
alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
alert("The Child HTML is: " + event.target.outerHTML);
}
render() {
return (
<div>
{this.props.childrenData.map(child => (
<Child
key={child.childNumber}
text={child.childText}
onClick={e => this.handleChildClick(child,e)}
/>
))}
</div>
);
}
}
그러나 상태를 관리 할 필요가없는 경우 단순화 할 수도 있습니다.
const Parent2 = ({childrenData}) => (
<div>
{childrenData.map(child => (
<Child
key={child.childNumber}
text={child.childText}
onClick={e => {
alert("The Child button data is: " + child.childText + " - " + child.childNumber);
alert("The Child HTML is: " + e.target.outerHTML);
}}
/>
))}
</div>
)
JS 피들
PERF 경고 당신이 사용하는 경우 : (ES5 / ES6에 적용) PureComponent
또는 shouldComponentUpdate
사용하기 때문에 위의 구현은 기본적으로 최적화되지 않습니다 onClick={e => doSomething()}
, 또는 렌더링 단계에서 직접 바인딩은 부모가 렌더링 새로운 기능 매번를 만들 수 있기 때문에. 앱에서 성능 병목 현상이 발생하면 데이터를 하위 항목으로 전달하고 "안정된"콜백 (부모 클래스에서 설정 this
하고 클래스 생성자에서 바인딩) 내에 데이터를 다시 삽입하여 PureComponent
최적화를 시작할 수 있습니다. shouldComponentUpdate
소품 비교 검사에서 자신의 구현을 수행 하고 콜백을 무시할 수 있습니다 .
또한 재구성 라이브러리를 사용 하여 고급 구성 요소를 제공하여 미세 조정 된 최적화를 달성 할 수 있습니다.
// A component that is expensive to render
const ExpensiveComponent = ({ propA, propB }) => {...}
// Optimized version of same component, using shallow comparison of props
// Same effect as React's PureRenderMixin
const OptimizedComponent = pure(ExpensiveComponent)
// Even more optimized: only updates if specific prop keys have changed
const HyperOptimizedComponent = onlyUpdateForKeys(['propA', 'propB'])(ExpensiveComponent)
이 경우 다음을 사용하여 하위 구성 요소를 최적화 할 수 있습니다.
const OptimizedChild = onlyUpdateForKeys(['text'])(Child)