ReactJS - 更新后子级无法访问父级状态

Posted

技术标签:

【中文标题】ReactJS - 更新后子级无法访问父级状态【英文标题】:ReactJS - Child unable to access parent state after update 【发布时间】:2020-06-26 20:46:29 【问题描述】:

我在子组件中有一个 input field,它是从父状态的值预填充的。

由于我将当前值作为 prop 和函数在父级中更新此值传递给子级,因此似乎每当我从传递的函数更新父级时,我的子级突然无法访问父级状态.

我父母的状态:

  const [blockList,setBlockList] = useState(
    "0":
      type:"loading",
      content:
        'title':"placeholder_title",
        'description':"placeholder_description"
      
    ,
    "1":
      type:"description",
      content:
        'title':"placeholder_title",
        'description':"placeholder_description"
      
    ,
    "2":
      type:"skills_and_requirements",
      content:
        'title':"",
        'description':""
      
    ,
  )

传递给子函数的函数:

const _getBlockContent = (
  currentBlockKey, 
  contentKey, 
  returnedContent
) => 
  setBlockList(blockList[currentBlockKey].content[contentKey] = returnedContent)

我传递给孩子的东西:

  return (    
      <Child
        currentBlock=blockList[selectedBlock] // (i.e. selectedBlock = '1')
        _getBlockContent=_getBlockContent
        currentBlockKey=selectedBlock // (i.e. selectedBlock = '1')
      /> )

现在,每当我将输入保存在孩子中并使用函数_getBlockContent 更新我父母的状态时,这都会导致我的孩子崩溃。

TypeError: props.currentBlock.content is undefined

完整的孩子(draftJS):

const EditorPanel = (props) => 

  //receives the block from the parent. The block type will define the advice and other static elements of the pannel. The block content will define what to include in the input and editor fields.
  //This function should be passed to the editor and update the block content. 
  const _getEditorContent = (contentKey, returnedContent) => 
    console.log("contentKey is: %s", contentKey);
    console.log("returnedContent is: %s", returnedContent);
    props._getBlockContent(props.currentBlockKey,contentKey, returnedContent)
  

  return(
    <div className="edit_panel">
      <div className="edit_panel_container">
        <h2>Description</h2>
        <h3>Title</h3>
        <MyEditor 
          contentKey='title'
          contentValue=props.currentBlock.content['title']
          _getEditorContent=_getEditorContent
        />
        <p>Title of this section should be eiusmod  dolor sit amet, consectetur.</p>
        <h3>Description</h3>
        <MyEditor 
          contentKey='description'
          contentValue=props.currentBlock.content['description']
          _getEditorContent=_getEditorContent
        />

        <p
        >Title of this section should be eiusmod  dolor sit amet, consectetur.</p>
        <p>Title of this section should be eiusmod  dolor sit amet, consectetur.</p>
      </div>
    </div>
  );
;


class MyEditor extends React.Component 
  constructor(props) 
    super(props);
    //this.state = editorState: EditorState.createEmpty();
    this.state = editorState: EditorState.createWithContent(
      stateFromhtml(props.contentValue)
    );
    this.onChange = editorState => 
      this.setState(editorState);
      //this.returnEditorHTML()
    
    this.handleKeyCommand = this.handleKeyCommand.bind(this);
    this.focus = () => this.editor.focus();
    this.returnEditorHTML = editorState => 
      const content = stateToHTML(this.state.editorState.getCurrentContent());
      props._getEditorContent(props.contentKey,content);
    ;
  



  handleKeyCommand(command, editorState) 
    const newState = RichUtils.handleKeyCommand(editorState, command);

    if (newState) 
      this.onChange(newState);
      return 'handled';
    

    return 'not-handled';
  

  _onBoldClick() 
    this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, 'BOLD'));
  

  _onItalicClick() 
    this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, 'ITALIC'));
  

  _onUnderlineClick() 
    this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, 'UNDERLINE'));
  

  render() 
    return (
      <div>
        <div className="draft_input">
          <Editor 
            editorState=this.state.editorState
            handleKeyCommand=this.handleKeyCommand
            onChange=this.onChange 
          />
        </div>
        <button onClick=this._onItalicClick.bind(this)>I<i className="fas fa-bold"></i></button>
        <button onClick=this._onBoldClick.bind(this)>B</button>
        <button onClick=this._onUnderlineClick.bind(this)>U</button>
        <button onClick=this.returnEditorHTML>save</button>
        <div></div>
      </div>
    );
  

【问题讨论】:

为了完整起见,能否分享一下 Child JS 的代码。 @RamGrandhi 谢谢!我在最初的帖子下方添加了完整的孩子。 @RamGrandhi 实际上主父级有 2 个级别 【参考方案1】:

在您的_getBlockContent 函数中,您将整个状态替换为returnedContent,而您只需要替换您想要更新的键:

const _getBlockContent = (
  currentBlockKey, 
  contentKey, 
  returnedContent
) => 
  const newBlockList = 
    ...blockList,
    [currentBlockKey]: 
        ...blockList[currentBlockKey],
        [contentKey]: returnedContent,
    
  ;
  setBlockList(newBlockList);

由于您的 _getBlockContent 实际更新状态,您应该考虑将其重命名为 setBlockContentonBlockContentChanged 以使其比执行写入而不是读取更清晰

【讨论】:

【参考方案2】:

我看到了什么。

按照您的命名,_getBlockContent(..) 用于检索状态。 请注意,setBlockList(..) 不用于读取状态,它仅用于更新状态。要读取状态,您可以直接在函数组件_getBlockContent(..) 中使用blockList,如下所示。

    return blockList[currentBlockKey].content[contentKey];

除此之外,为了主动重现您的错误,您能否分享一个 github 链接或包含逻辑中所有组件的内容(包括 等)?

【讨论】:

以上是关于ReactJS - 更新后子级无法访问父级状态的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript | ReactJS:父状态更改不触发子道具更新

防止子级在更新父级状态时重新渲染,使用父级方法作为本机反应的道具

在 ReactJs 中,从 redux 存储或从父级到子级将 props 传递给子组件的最佳实践是啥?

使用图像的 SRC 将子级传递给父级时出现问题。反应 JS

父级暂停和子级恢复后雪花子任务未运行

reactjs checkboxlist组件 - 更新父级中的状态更改