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

时间:2020-03-15 14:47:50

标签: javascript reactjs components react-hooks

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

由于我将当前值作为道具传递给了孩子,并且将其作为函数更新了父级中的该值,因此似乎每当我从传递的函数中更新父级时,我的孩子突然就无法访问父级状态

我父母的状态:

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

2 个答案:

答案 0 :(得分:0)

我看到了一些东西。

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

    return blockList[currentBlockKey].content[contentKey];

除此之外,要主动重现您的错误,您是否可以共享github链接或逻辑中包含所有组件的内容(包括等)?

答案 1 :(得分:0)

_getBlockContent函数中,将整个状态替换为returnedContent,而只需要替换要更新的密钥:

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

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