React -通过传递props改变输入defaultValue

React - change input defaultValue by passing props

本文关键字:改变 输入 defaultValue props -通 React      更新时间:2023-09-26

考虑这个例子:

var Field = React.createClass({
    render: function () {
        // never renders new value...
        return (
            <div>
                <input type="text" defaultValue={this.props.value || ''} />
            </div>
        );
    }
});
var App = React.createClass({
    getInitialState: function () {
        return {value: 'Hello!'};
    },
    changeTo: function (str) {
        this.setState({value: str});
    },
    render: function () {
        return (
            <div>
                <Field value={this.state.value} />
                <button onClick={this.changeTo.bind(null, 'Whyyyy?')}>Change to "Whyyyy?"</button>
                <button onClick={this.changeTo.bind(null, void 0)}>Change to undefined</button>
            </div>
        );
    }
});
React.render(
    <App />,
    document.getElementById('app')
);

我想把value传递给defaultValue作为哑输入组件的prop。然而,它从不重新渲染它。

正如前面提到的,defaultValue仅在表单的初始加载时被设置。在此之后,它将不会得到"自然"更新,因为意图只是设置一个初始默认值。

如果需要,可以通过将key传递给包装器组件来解决这个问题,就像在FieldApp组件上一样,尽管在更实际的情况下,它可能是form组件。一个好的key应该是传递给表单的资源的唯一值——例如,就像存储在数据库中的id一样。

在您的简化情况下,您可以在您的字段渲染中这样做:

<div key={this.props.value}>
    <input type="text" defaultValue={this.props.value || ''} />
</div>

在一个更复杂的表单情况下,像这样的东西可能会得到你想要的,例如,你的onSubmit动作提交给一个API,但留在同一个页面:

const Form = ({item, onSubmit}) => {
  return (
    <form onSubmit={onSubmit} key={item.id}>
      <label>
        First Name
        <input type="text" name="firstName" defaultValue={item.firstName} />
      </label>
      <label>
        Last Name
        <input type="text" name="lastName" defaultValue={item.lastName} />
      </label>
      <button>Submit!</button>
    </form>
  )
}
Form.defaultProps = {
  item: {}
}
Form.propTypes = {
  item: PropTypes.object,
  onSubmit: PropTypes.func.isRequired
}

当使用不受控制的表单输入时,我们通常不关心这些值,直到它们被提交之后,所以这就是为什么只有当你真的想要更新defaultValues时才强制重新渲染(在提交之后,而不是在每次更改单个输入时)。

如果您也在编辑相同的表单,并且担心API响应可能返回不同的值,您可以提供一个组合键,例如id加时间戳。

defaultValue仅适用于初始加载。之后就不会更新了。您需要为您的字段组件维护状态:

var Field = React.createClass({
    //transfer props to state on load
    getInitialState: function () {
        return {value: this.props.value};
    },
    //if the parent component updates the prop, force re-render
    componentWillReceiveProps: function(nextProps) {
         this.setState({value: nextProps.value});
    },
    //re-render when input changes
    _handleChange: function (e){
        this.setState({value: e.target.value});
    },
    render: function () {
        // render based on state
        return (
            <div>
                <input type="text" onChange={this._handleChange} 
                                   value={this.state.value || ''} />
            </div>
        );
    }
});

我相当确定这与受控与非受控输入有关。

如果我理解正确,因为您的<input>是不受控制的(不定义value属性),那么该值将始终解析为初始化的值。本例中为Hello! .

为了克服这个问题,您可以添加value属性并在onChange:

中设置它。
var Field = React.createClass({
      render: function () {
          // never renders new value...
          return (
              <div>
                  <input type="text" defaultValue={this.props.default || ''} value={this.props.value} />
              </div>
          );
      }
  });

这是显示变化的柱塞。

您可以有条件地进行输入,然后每次您想强制更新defaultValue时,您只需要卸载输入,然后立即再次呈现它。

这里的问题是:

onClick={this.changeTo.bind(null, 'Whyyyy?')}

我很好奇为什么你绑定到null

你想绑定到'this',这样changeTo就会在this对象中setState。

试试这个

<button onClick={this.changeTo.bind(this, 'Whyyyy?')}>Change to "Whyyyy?"</button>
<button onClick={this.changeTo.bind(this, void 0)}>Change to undefined</button>

在Javascript中,当一个函数被调用时,它在它被调用的地方被调用,而不是在它被编写的地方(我知道,似乎违反直觉)。为了确保它在你编写它的上下文中被调用,你需要'.bind(this)'。

要了解更多关于绑定和函数作用域的知识,有很多在线教程,(有些比其他的要好得多)-你可能会喜欢这个:http://ryanmorr.com/understanding-scope-and-context-in-javascript/

我还建议使用React Dev工具,如果你使用firefox或chrome,这样你就可以看到状态。消息没有改变:https://facebook.github.io/react/blog/2015/09/02/new-react-developer-tools.html

使用条件渲染,那么组件将加载正确的初始值。比如在这个模块中:

class MenuHeaderInput extends React.Component{
    constructor(props){
        super(props);
        this.handleBlur = this.handleBlur.bind (this);
    }
    handleBlur (e) {
        this.props.menuHeaderUpdate(e.target.value);
    }
    render(){
        if (this.props.menuHeader) {
            return (
                <div className="w3-row w3-margin" onClick = {() => this.props.handleTitleClick (10)}>
                    <div className="w3-third" ><pre></pre></div>
                    <input
                        className = {"w3-third w3-input w3-jumbo " + EDIT_COLOR}                
                        type = "text"
                        defaultValue = {this.props.menuHeader}
                        onBlur = {this.handleBlur}
                    />
                    <div className="w3-third" ><pre></pre></div>                
                </div>
            )
        }
        else {
            return null;
        }
    }
}

与Sia的精彩回答相关:https://stackoverflow.com/a/41962233/4142459.

对于我来说,我有几种方法可以更新表单:

  1. 用户可以在表单字段中输入值
  2. 一个API请求允许用户从以前的版本恢复
  3. 用户可以导航到已填写的表单(使用URL的queryParams)
  4. 清除表单字段
  5. 等更多的方式允许所有字段或只是一个单一的变化发生从用户操作或websockets。

我发现确保表单的状态反映在它的输入中最简单的方法确实是:

  1. 在表单的顶层或表单的父元素上提供一个手动控制的key prop(只要它在DOM树的输入之上)。
  2. 当用户输入key时,不需要进行更新。
  3. 我使key是一个简单的formHistoricalVersion,并作为某些更新外部的用户输入/选择/等与表单字段的值发生交互,我增加了formHistoricalVersion。
  4. 这确保了表单的状态,无论是由用户操作还是由API请求是同步的——我完全控制它。

我尝试过的其他解决方案:

  1. 当发出API请求时,使整个表单消失(当加载时更改为加载旋转器而不是表单)。缺点的性能和clearForm,这是有点疯狂,但可能与setImmediate转换为加载旋转器的形式,当他们第一次清除它,然后设置isLoading回到false在setimate。
  2. 在每次输入上添加key:这工作得很好,但是每当用户输入时它都会有一个奇怪的光点,所以我不得不摆脱它。
  3. 为表单(field.id)放置一个静态密钥(正如上面的答案所建议的)并没有涵盖我所有的用例。
总之,使用react/redux设置表单的键非常容易,我只需要添加相当于:
return {
  ...state,
  formFieldState: payload.formFields,
  historicalFormVersion: state.historicalFormVersion + 1
}

这是必要的,因为我正在使用一些第三方库和我自己的数字输入,将value作为道具,但使用value作为defaultValue:

const NumberDisplay: FunctionComponent = ({ value, setValue }) => (
  <input
    defaultValue={convertToSpecialNumberDisplay(value)}
    onBlur={(e) => convertToSpecialNumberDisplay(e.target.value)}
    onFocus={(e) => convertToNumberFromDisplay(e.target.value)}
    onChange={(e) => setValue(e.target.value)}
  />
)

总体形式的近似还原:

const FullForm: FunctionComponent = () => {
  const dispatch = useDispatch();
  const formState = useState((state) => state.formState);
  const formHistoricalVersion = useState((state) => state.formHistoricalVersion);
  return (
  <form key={formHistoricalVersion}>
    {renderFormFields(formState, dispatch)}
  </form>
  )
}

我也面临这个问题,我所做的是在道具发生变化时手动更新输入值。把这个添加到你的Field react类中:

componentWillReceiveProps(nextProps){
    if(nextProps.value != this.props.value) {
        document.getElementById(<element_id>).value = nextProps.value
    }
}

你只需要给你的元素添加一个id属性,这样它就可以被定位了