簡體   English   中英

React 16.4-手動表單輸入填充以及它從getDerivedStateFromProps的更新?

[英]React 16.4 - manual form input fill along with its updates from getDerivedStateFromProps?

我在React 16.4上更新后遇到一個問題,其中我們使用getDerivedStateFromProps邏輯進行了一些重大更改。 現在,它將在傳入組件和自己組件的props上的每個組件更新上觸發。

因此,我已經閱讀了文檔和手冊,但仍然無法弄清表單輸入字段應基於傳入的道具( controlled component ),並且同時能夠由用戶自己的輸入進行修改的情況?

我也嘗試過這篇文章,但是它只涉及一次性更新的情況,而不是手動輸入的情況: 為什么在setState之后調用getDerivedStateFromProps?

這是我要重現的小代碼:

import PropTypes from 'prop-types'
import React from 'react'

export class NameEditor extends React.Component {
  static propTypes = {
    currentLevel: PropTypes.number
  }

  static defaultProps = {
    currentLevel: 0
  }

  constructor(props) {
    super(props)

    this.state = {
      currentLevel: 0
    }
  }

  static getDerivedStateFromProps(nextProps) {
    return {
      currentLevel: nextProps.currentLevel
    }
  }

  _handleInputChange = e => {
    this.setState({
      currentLevel: e.target.value
    })
  }

  render() {
    const { currentLevel } = this.state

    return (
        <input
          placeholder={0}
          value={currentLevel}
          onChange={this._handleInputChange}
        />
    )
  }
}

export default NameEditor

更新:

當前, _handleInputChange方法將僅修改子組件的狀態,該子組件將調用getDerivedStateFromProps

該方法的工作方式是,它在每個newPropssetState調用發生時被調用。

因此,其行為如下:

  1. 您可以通過處理程序更改該值。
  2. 調用getDerivedStateFromProps get,它將從父組件獲取currentLevel值,該父組件仍未進行修改,因為我們未在其中進行任何更改,因此,它將使用調用程序中存在的值覆蓋來自調用處理程序的新值。父組件,未修改。

解決此問題的方法:我們將需要一個來自父組件的回調函數,該函數的功能與handleInputChange相同。

所以:

  1. 向您的父組件添加一個handleCurrentLevelChange方法,該方法將僅具有一個參數e.target.value ,其作用是在狀態下修改currentLevel
  2. 將您創建的handleCurrentLevelChange傳遞給handleCurrentLevelChange 所需的名稱,可能是相同的名稱。
  3. 修改您的孩子的 handlr,如下所示:
  _handleInputChange = (e, cb) => {
    this.setState({
      currentLevel: e.target.value
    }, () => {
      cb && cb(e.target.value) //this makes the callback optional.
    });
  }
  1. 修改您的onChange屬性以適應新的更新:
        <input
          placeholder={0}
          value={currentLevel}
          onChange={(e) => this._handleInputChange(e, handleCurrentLevelChange)}

onChange屬性和處理程序的新行為將允許您的孩子和父母都進行更改。

這應該解決當前的問題。

解決方案#1(帶鍵和重新安裝):

您可能需要根據傳入的currentLevel為其提供一個密鑰,以在每個外部props更新中重新安裝當前組件。 它看起來像:

class Wrapper ... {
...

  render() {
    const { currentLevel } = this.props;

    return (
     <NameEditor key={currentLevel} {...currentLevel} />
    )
  }
}

export default Wrapper

...並在組件上進行一些額外的更改,以通過告知它來阻止派生的props替換-是否是第一次渲染(因為我們計划僅通過內部重裝來控制其state ,而只能通過外部重裝來控制其state ,所以實際上是這樣) ):

import PropTypes from 'prop-types'
import React from 'react'

export class NameEditor extends React.Component {
  static propTypes = {
    currentLevel: PropTypes.number
  }

  static defaultProps = {
    currentLevel: 0
  }

  constructor(props) {
    super(props)

    this.state = {
      currentLevel: 0,
      isFirstRender: false
    }
  }

  static getDerivedStateFromProps(nextProps, prevProps) {
    if (!prevProsp.isFirstRender) {
      return {
        currentLevel: nextProps.currentLevel,
        isFirstRender: true
      };
    }

    return null;
  }

  _handleInputChange = e => {
    this.setState({
      currentLevel: e.target.value
    })
  }

  render() {
    const { currentLevel } = this.state

    return (
        <input
          placeholder={0}
          value={currentLevel}
          onChange={this._handleInputChange}
        />
    )
  }
}

export default NameEditor

因此,在這種情況下,您將有機會通過從表單手動輸入值來操縱組件狀態。

解決方案2(不按標志重新安裝)

嘗試設置一些標志,以在每次重新渲染時將外部(getDerived ...)和內部(Controlled Comp ...)狀態更新分開。 例如,通過updateType

import PropTypes from 'prop-types'
import React from 'react'

export class NameEditor extends React.Component {
  static propTypes = {
    currentLevel: PropTypes.number
  }

  static defaultProps = {
    currentLevel: 0
  }

  constructor(props) {
    super(props)

    this.state = {
      currentLevel: 0,
      updateType: 'props' // by default we expecting update by incoming props
    } 
  }

  static getDerivedStateFromProps(nextProps, prevProps) {
    if (!prevState.updateType || prevState.updateType === 'props') {
      return {
        updateType: 'props',
        currentLevel: nextProps.currentLevel,
        exp: nextProps.exp
      }
    }

    if (prevState.updateType === 'state') {
      return {
        updateType: '' // reset flag to allow update from incoming props
      }
    }

    return null
  }

  _handleInputChange = e => {
    this.setState({
      currentLevel: e.target.value
    })
  }

  render() {
    const { currentLevel } = this.state

    return (
        <input
          placeholder={0}
          value={currentLevel}
          onChange={this._handleInputChange}
        />
    )
  }
}

export default NameEditor

PS這可能是一種反模式(希望Dan永遠不會看到這一點),但現在我無法找到更好的解決方案。

解決方案#3

請參閱Sultan H.下一篇文章,關於具有包裝器組件顯式回調的受控邏輯。

因為在設置狀態之后,React會調用渲染,但是在渲染之前,您總是會調用getDerivedStateFromProps方法。

setState計划對組件狀態對象的更新。 狀態改變時,組件通過重新渲染做出響應

在初始安裝和后續更新上,都在調用render方法之前立即調用getDerivedStateFromProps。 它應該返回一個對象以更新狀態,或者返回null則不更新任何內容。

https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM