在我的 React 应用程序中将函数作为道具传递时,我遇到了一个奇怪的问题。 代码如下:
const NewPage = () => {
const [blocks, setBlocks] = useState([]);
const [needsShowImageModal, setNeedsShowImageModal] = useState(false);
const textButtonHandler = () => {
const key = randomInt(0, 1000000000);
const array = blocks.concat({ key, deleteButtonHandler: deleteButtonHandler });
setBlocks(array);
};
function deleteButtonHandler(blockKey) {
// Test functionality, if one text field was added arrray size should
// be 1
console.log(blocks.length);
}
return (
<div>
<ImageModal
show={needsShowImageModal}
onHide={() => setNeedsShowImageModal(false)}
insertButtonHandler={insertImageHandler}
/>
<div className="d-flex">
<NewPageSidebar
textButtonHandler={textButtonHandler}
imageButtonHandler={imageButtonHandler}
spacingButtonHandler={spacingButtonHandler}
/>
<NewPageContent blocks={blocks} />
</div>
</div>
);
};
export default NewPage;
当调用文本按钮处理程序(按下按钮(时,我将一个新的数据模型添加到blocks
数组中。我有另一个按钮处理程序deleteButtonHandler
传递给NewPageContent
组件(在数据模型内(。NewPageContent
:
const NewPageContent = ({ blocks }) => {
return (
<div className="new-page-content-container border mr-5 ml-5 p-3">
{blocks.map(block =>
<TextBlock
key={block.key}
blockKey={block.key}
deleteButtonHandler={block.deleteButtonHandler}
/>
)}
</div>
);
};
NewPageContent.propTypes = {
blocks: PropTypes.arrayOf(PropTypes.element)
};
export default NewPageContent;
最后这个处理程序传递给TextBlock
:
const TextBlock = ({ deleteButtonHandler, blockKey }) => {
const [editorState, setEditorState] = useState(
() => EditorState.createEmpty(),
);
const toolbarClickHander = (buttonType, e) => {
e.preventDefault();
switch (buttonType) {
case 'delete':
// Delete button handler called here
deleteButtonHandler(blockKey);
break;
default:
break;
}
};
return(
<div className='text-block'>
<TextBlockToolbar clickHandler={toolbarClickHander} />
<Editor
editorState={editorState}
onChange={setEditorState}
/>
</div>
);
};
如果我通过textButtonHandler
添加一个元素到blocks
,则该组件将按预期呈现在屏幕上。但是,如果我点击删除按钮并调用deleteButtonHandler
它会将数组的大小记录为0
,奇怪的是,如果我添加第二个元素然后点击该元素的删除按钮,如果将数组大小记录为1
.这几乎就像是拍摄blocks
状态的快照,就像将新textButtonHandler
分配给道具一样,而不是使用blocks
的实际当前状态。知道我可能在这里做错了什么吗?以前没有遇到过这个问题。谢谢
好的。这里发生了什么:
在对象中传递函数。该对象可能有自己的上下文,并且您尝试在该对象上下文中使用该函数,这会使反应变得混乱。(我知道 ECMAScript 简单对象没有自己的上下文,但 react 可能会处理这些数据,所以可能会以不同的方式工作。
因此,在子组件中传递每个函数的独立道具。
示例:https://codesandbox.io/s/broken-waterfall-vgcyj?file=/src/App.js:0-1491
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [blocks, setBlocks] = useState([
{ key: Math.random(), deleteButtonHandler }
]);
const textButtonHandler = () => {
const key = Math.random();
// const array = blocks.concat({
// key,
// deleteButtonHandler: deleteButtonHandler
// });
setBlocks(prev => prev.concat({ key, deleteButtonHandler }));
};
const deleteButtonHandler = blockKey => {
// Test functionality, if one text field was added arrray size should
// be 1
console.log(blocks.length);
};
return (
<div>
<div className="d-flex">
<NewPageContent
deleteButtonHandler={deleteButtonHandler}
blocks={blocks}
/>
</div>
<button onClick={textButtonHandler}>Handler</button>
</div>
);
}
const NewPageContent = ({ blocks = [], deleteButtonHandler = () => null }) => {
return (
<div className="new-page-content-container border mr-5 ml-5 p-3">
{blocks.map(block => (
<TextBlock
key={block.key}
blockKey={block.key}
// deleteButtonHandler={block.deleteButtonHandler}
deleteButtonHandler={deleteButtonHandler}
/>
))}
</div>
);
};
const TextBlock = ({ deleteButtonHandler = () => null, blockKey = "" }) => {
return (
<div className="text-block">
{blockKey}
<span onClick={deleteButtonHandler}>X</span>
</div>
);
};
我已经安慰了您的旧解决方案,以进行比较。