【问题标题】:React: props.itemId returns different value vs variable that uses props.itemId反应:props.itemId 返回不同的值与使用 props.itemId 的变量
【发布时间】:2019-05-19 00:11:57
【问题描述】:

目前

我有一个子组件 ItemField(参见下面的代码),它从父组件获取 this.props.itemId,并检查是否填充了 this.props.itemId,并根据检查即

itemId = this.props.itemId ? this.props.itemId : "new";

问题

在应用程序上移动项目列表中项目位置的排序操作,导致this.props.itemIdthis.itemId 返回控制台日志确认的不同值。 this.props.itemId 具有正确的值,但 this.itemId 包含该位置项的原始值。

ItemField.js

class ItemField extends Component {

  constructor(props) {
    super(props);
    this.state = {
      //temp value of inputs
      }
    }

  componentDidMount() {
    //no actions on did mount
  }

  //issueId to be Updated
  //if "new", then a new issue will be updated
  itemId = this.props.itemId ? this.props.itemId : "new";

  render() {
    console.log("this.props.itemId = " + this.props.itemId); //logs "1111"
    console.log("this.itemId = " + this.itemId); //should log "1111" i.e. same as above, but this doesn't always happen

    return (
      <div
        id={this.itemId}
      >{showValue}
      </div>
    )
  }
}

export default ItemField;

问题

我在上面的脚本中有 2 个 console.log 行,在某些情况下(例如,在对项目列表进行排序之后)返回不同的值。这些应该始终相同。这可能是什么原因?

注意事项:

  1. 我尝试将itemId = this.props.itemId ? this.props.itemId : "new" 行移到构造函数和componentDidMount 中,但这并没有解决问题。
  2. 我没有映射父组件中的所有 ItemField,而是为每个组件显式创建一个组件,例如&lt;ItemField value={this.props.item.name} itemId={this.props.item.id} /&gt; 其中name 是字段值,id 是传递给所有字段的 itemId。

组件结构

【问题讨论】:

  • 能否复制父组件中ItemFields 映射的部分?
  • 我目前没有映射所有ItemFields,而是明确地为每个人创建一个组件,例如&lt;ItemField value={this.props.item.name} itemId={this.props.item.id} /&gt; 其中name 是字段值,id 是传递给所有字段的itemId
  • @Wronski 有点像在黑暗中拍摄,但您是否考虑过在渲染方法中移动 itemId 定义?常量 itemId = this.props.itemId ? this.props.itemId : "新";
  • @ChristopherNgo,这是我最初的想法,但我认为有一种更简洁的方法可以做到这一点,代码的读者可以看到渲染上方组件的所有变量。仅供参考,我进行了重构(即在渲染中计算的变量),它可以工作:P

标签: reactjs


【解决方案1】:

它不会在运行一次时更新,以确保两者始终具有相同的值移动

itemId = this.props.itemId ? this.props.itemId : 'new';

在状态中渲染或保存它并使用getDerivedStateFromProps更新值。

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>

<script type="text/babel">
class ItemField extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      //temp value of inputs
      itemId: '',
    };
  }

  componentDidMount = () => {
    //no actions on did mount
    this.setState({
      itemId: this.props.itemId ? this.props.itemId : 'new'
    })
  }


  //issueId to be Updated
  //if "new", then a new issue will be updated

  static getDerivedStateFromProps = (props, state) => {
    // compare props with state data
    // if they are not equal return props
    // or return null
    // more info here https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
    
    if (props.itemId !== state.itemId) {
      return props;
    }
    return null;
  }

  render() {
    console.log('this.props.itemId = ' + this.props.itemId); //logs "1111"
    console.log('this.state.itemId = ' + this.state.itemId); //should log "1111" i.e. same as above, but this doesn't always happen

    return <div id={this.itemId}>{'showValue'}</div>;
  }
}

class App extends React.Component {

  state = {
    id: 1111
  }

  render() {
    return (
      <div>
        <button onClick={() => this.setState({ id: 2233 })}>Update ID</button>
        <ItemField value={'James'} itemId={this.state.id} />
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById('root'));
</script>

【讨论】:

  • 这就是我所追求的,但似乎有很多额外的代码来解决这个(我认为这是常见的)问题。推荐的模式是什么? (1)在render()中定义或者(2)比较state和props,然后均衡?或者(3)是我的设计导致了这个问题,我应该避免这种设计吗?
  • 我喜欢做的一件事是在子组件中没有状态,直接从 props 中访问值。我看不出 1 和 2 之间的区别,因为 getDerivedStateFromProps 总是在渲染之前被调用。
  • 听起来您建议在render() 中定义这些变量。我的问题是,该组件包含许多重复使用itemId 的组件独有的方法(在检查它是从道具填充后),我不想在每个方法中重新运行此计算。我需要的是一个计算位置。
  • 如果是这种情况,请使用 2.
  • getDerivedStateFromProps 总是在渲染之前运行,在这里您可以比较值并在必要时重新渲染。
【解决方案2】:

MOVE ITEMID内的状态AKA̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶s̶̶̶t̶̶̶a̶̶̶t̶̶̶e̶̶̶̶̶̶=̶̶̶{̶̶̶ITEMID:̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶p̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶.̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶}̶̶̶和实施̶̶̶̶̶̶̶̶̶̶̶̶̶̶̶̶̶̶̶̶̶̶c̶̶̶o̶̶̶m̶̶̶p̶̶̶o̶̶̶n̶̶̶e̶̶̶n̶̶̶t̶̶̶D̶̶̶i̶̶̶d̶̶̶U̶̶̶p̶̶̶d̶̶̶a̶̶̶t̶̶̶e̶̶̶(̶̶̶p̶̶̶r̶̶̶e̶̶̶v̶̶̶P̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶,̶̶̶ ̶̶̶p̶̶̶r̶̶̶e̶̶̶v̶̶̶S̶̶̶t̶̶̶a̶̶̶t̶̶̶e̶̶̶,̶̶̶ ̶̶̶s̶̶̶n̶̶̶a̶̶̶p̶̶̶s̶̶̶h̶̶̶o̶̶̶t̶̶̶)̶̶̶{̶̶̶ ̶̶̶ ̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶i̶̶̶f̶̶̶ ̶̶̶(̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶p̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶.̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶ ̶̶̶!̶̶̶=̶̶̶=̶̶̶ ̶̶̶p̶̶̶r̶̶̶e̶̶̶v̶̶̶P̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶.̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶)̶̶̶ ̶̶̶{̶̶̶ ̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶s̶̶̶e̶̶̶t̶̶̶S̶̶̶t̶̶̶a̶̶̶t̶̶̶e̶̶̶(̶̶̶{̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶:̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶p̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶.̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶}̶̶̶)̶̶̶ ̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶}̶̶̶ ̶̶ ̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶}̶̶̶̶̶̶ P>

为什么你甚至需要 itemId 老实说?直接使用 props 即可。

 return (
  <div
    id={this.props.itemId || 'new' }
  >{showValue}
  </div>
)

【讨论】:

  • 我没有包含所有代码,但我在组件的许多方法中都使用了itemId,并且更容易定义一次而不是每次都重新计算。
  • 这个constructor({ itemId = 'new'}) {... 怎么样,然后到处推送 temId。
猜你喜欢
  • 2019-01-03
  • 1970-01-01
  • 1970-01-01
  • 2017-04-28
  • 1970-01-01
  • 2021-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多