我需要一些帮助来理解 onClick EventHandler 的以下工作代码。详细的解释将有助于理解为什么一个函数在这里返回另一个函数。
const MyComponent = (props) => {
const onClickHandler = (somearg) => (e) => {
console.log(`somearg passed successfully is ${somearg}`)
};
return (
<div onClick={onClickHandler(somearg)}>
</div>
);
};
export default MyComponent;
Run Code Online (Sandbox Code Playgroud)
Bri*_*son 13
您所指的模式称为“柯里化”。我将在稍后的答案中解释为什么该模式很有用,但首先让我们尝试准确理解发生了什么。
正如您已经确定的,该onClickHandler函数返回一个新函数,除此之外它实际上并没有添加太多内容。现在这意味着当组件呈现时,onClickHandler将立即调用。所以写这个:
<div onClick={onClickHandler('test')}>
Run Code Online (Sandbox Code Playgroud)
最终会返回这个:
<div onClick={(e) => {console.log(`somearg passed successfully is ${somearg}`)}}>
Run Code Online (Sandbox Code Playgroud)
这就是为什么在这里您可以调用 JSX 中的函数,尽管(就像您指出的那样)大多数其他时候您不能这样做。原因是因为返回的函数将实际处理点击。
现在让我们更多地讨论一下为什么这个模式很有用。somearg是模糊的,但我们现在会坚持下去,直到我们得到其他好处。
“currying” 使用 aclosure来“冻结” 的值somearg以供返回的函数使用。查看上面返回函数的示例,somearg似乎不存在。然而,通过关闭,somearg不仅可用,而且还保留 的值'test'。
此模式允许您以其他不可能的方式重用函数。考虑一个用例,其中我们有 2div应该是可点击的。它们都应该做同样的事情,但是能够区分单击了哪个 div 来完成该操作可能会有所帮助。
为了简单起见,我们假设我们有两个div,当单击时我们希望每个都记录他们的订单。
以下是您无需柯里化即可做到这一点的方法:
const Example = () => {
const onClickHandler1 = (e) => {
console.log("I am the 1 div.");
};
const onClickHandler2 = (e) => {
console.log("I am the 2 div.");
};
return (
<div>
<div onClick={onClickHandler1}>1</div>
<div onClick={onClickHandler2}>2</div>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById('root'));Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>Run Code Online (Sandbox Code Playgroud)
上面的效果很好,但是我们的两个函数有很多共享功能。似乎没有必要两者兼而有之。因此,一种解决方案是使用柯里化:
const Example = () => {
// Converted to longer form so its possible to console.log in the first function
// It still operates identically to the short-hand form.
const onClickHandler = (order) => {
console.log("called with " + order);
return (e) => console.log("I am the " + order + " div.");
};
return (
<div>
<div onClick={onClickHandler(1)}>1</div>
<div onClick={onClickHandler(2)}>2</div>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById('root'));Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>Run Code Online (Sandbox Code Playgroud)
正如您在上面的示例中看到的,onClickHandler组件渲染后就会被调用两次。但第一次order是“冻结”或“关闭”,值为1,第二次值为2。
这是一个非常简单的示例,但想象一下您正在循环一组动态数据,每个数据都应返回一个可单击元素。然后,您可以传递索引或 id 或其他变量来标识该元素。
最终,这只是函数重用的一种模式。还有其他方法可以实现相同级别的抽象,例如使用内联函数,但这只是为了解释柯里化及其使用方式。
这就是代码第一次运行时发生的情况
const MyComponent = (props) => {
const onClickHandler = (somearg) => (e) => {
console.log(`somearg passed successfully is ${somearg}`)
};
return (
<div onClick={onClickHandler('some args')}>
</div>
);
};
Run Code Online (Sandbox Code Playgroud)
当它看到它时,onClick={onClickHandler(1)}它将运行里面的代码onClick
然后onClickHandler是一个函数,我们传递一个参数 as1并执行它,现在它将返回另一个具有替换值的函数,如下所示。
(e) => {
console.log(`somearg passed successfully is 1`); // see args gets replaced with the value.
}
Run Code Online (Sandbox Code Playgroud)
所以现在当我们点击 div 时,上面的函数就会被调用。
为了确保这确实发生了,请参阅下面的演示
const MyComponent = (props) => {
const onClickHandler = (somearg) => (e) => {
console.log(`somearg passed successfully is ${somearg}`, new Date().getTime())
};
return (
<div onClick={onClickHandler(new Date().getTime())}>
div
</div>
);
};
Run Code Online (Sandbox Code Playgroud)
你会看到时间不同,这意味着点击时间和函数创建时间不同。
因此,如果您在 onClick 中放置一个函数,因为它会随着代码的执行而执行,并且不会响应您的点击
const MyComponent = (props) => {
const onClickHandler = (e) => {
console.log(`somearg passed successfully is`, new Date().getTime())
};
return (
<div onClick={onClickHandler(new Date().getTime())}>
div
</div>
);
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3678 次 |
| 最近记录: |