将函数作为 prop 传递,在调用函数时它没有获得正确的值

Passing a function as a prop, when calling the function it doesn't get the correct values

我在 React 应用程序中将函数作为 prop 传递时遇到一个奇怪的问题。代码如下:

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>
    );
    
};

如果我通过 textButtonHandlerblocks 添加一个元素,组件将按预期呈现在屏幕上。但是,如果我点击删除按钮并调用 deleteButtonHandler,它会将数组的大小记录为 0,奇怪的是,如果我添加第二个元素,然后在记录数组大小时点击该元素的删除按钮作为 1。这几乎就像它正在拍摄 blocks 状态的快照,就像新的 textButtonHandler 被分配给 prop 而不是使用 blocks 的实际当前状态一样。任何想法我可能在这里做错了什么?以前 运行 没有处理过这个问题。谢谢

好的。这里发生了什么:

您在对象中传递函数。该对象可能有自己的上下文,而您尝试在该对象上下文中使用该函数,这会混淆反应。 (我知道 ECMAScript 简单对象没有自己的上下文,但 React 可能会处理该数据,因此可能会以不同的方式工作。)
所以,在子组件中传递每个函数独立的 prop。

示例: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>
  );
};

我安慰了你的老办法,拿来对比一下。