# 常见问题解答

## 组件同时传入受控props和非受控props

### 部分组件同时传入 value 和 defaultValue 属性

使用 `react@16.3` 版本之后，将 `componentWillReceiveProps` 改为 `getDerivedStateFromProps` 之后，如果同时传入 value 和 defaultValue 时，将会发现

初始 `value` 值为 `undefined` 时，defaultValue 并未起作用。

原因：

早期版本中，在 `constructor` 中会采用如下方式设置 state：

```js
constructor(props) {
  super(props);
  this.state = {
    // 此情况下，如果同时传入 value 和 defaultValue时，如果 value 为 undefined 或者 null 等 `false` 值时，会将 defaultValue 值设置为为 state.value
    value: props.value || props.defaultValue
  };
}

// 组件挂载时，不会执行该方法
componentWillReceiveProps(nextProps){
  if (this.state.value !== nextProps.value || this.props.value !== nextProps.value){
    this.setState({
      value: nextProps.value
    });
  }
}
```

新版本中，采用 `getDerivedStateFromProps` 代替 `componentWillReceiveProps`，由于在挂载时也会执行 `getDerivedStateFromProps`，因此 这两个方法中判断是否设置 state 的方式需要保持一致。

```js
constructor(props) {
  super(props);
  let value;
  // value 的优先级最高
  if (utils.isKeyInObject('value', props)) {
    value = props.value;
  } else if (utils.isKeyInObject('defaultValue', props)) {
    value = props.defaultValue;
  }
  this.state = {
    value
  };
}

// 组件挂载时，也会执行该方法。因此，该方法中返回的 state.value 值，将会覆盖 constructor 中配置的 state.value 值
static getDerivedStateFromProps(nextProps, prevState) {
  if (utils.isKeyInObject('value', nextProps) && nextProps.value !== prevState.value){
    return {
      value: nextProps.value
    };
  }
  return null;
}
```

针对早期同时设置 value 和 defaultValue 的解决办法：

上层组件，如果同时传入了 value 和 defaultValue 属性，修改为仅传入 value 属性，将 defaultValue 的值，自行处理，如：

```js
// 以前同时设置 value 和 defaultValue
class MyDemo extends Component {
  state = {};

  render (){
    const { value } = this.state;
    return <InputNumber value={value} defaultValue={3} onChange={v => this.setState({ value: v })} />;
  }
}

// 修改后，推荐
class MyDemo extends Component {
  state = {
    value: 3
  };

  render (){
    const { value } = this.state;
    return <InputNumber value={value} onChange={v => this.setState({ value: v })} />;
  }
}
```
