【问题标题】:React - change input defaultValue by passing propsReact - 通过传递道具更改输入 defaultValue
【发布时间】:2015-08-24 00:32:57
【问题描述】:

考虑这个例子:

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

我想将值传递给defaultValue 作为哑输入组件的道具。但是它永远不会重新渲染它。

【问题讨论】:

标签: javascript forms reactjs default-value


【解决方案1】:

正如前面提到的答案,defaultValue 仅在表单的初始加载时设置。之后,它不会“自然”更新,因为其目的只是设置一个初始默认值。

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

在您的简化情况下,您可以在 Field 渲染中执行此操作:

<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 加时间戳。

【讨论】:

  • 这应该是最好的答案
  • 你是一个救生员
  • 使用值作为键只是一种技巧,它会随着值的变化多次安装元素。虽然它可以解决您的问题,但它不是更新输入值的最佳方式。实际上它不会更新值,而是创建一个新值(在极端情况下会导致内存泄漏)。最好使用受控输入字段而不是此解决方案。
  • 你拯救了我的一天!
  • 这应该是最好的答案
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    我相当肯定这与Controlled vs. Uncontrolled inputs 有关。

    如果我理解正确,因为您的 &lt;input&gt; 是不受控制的(未定义 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>
              );
          }
      });
    

    Here is a plunker 显示更改。

    【讨论】:

    • 这是解决不受控制的输入的最干净的方法吗?此外,我在您的示例中没有看到任何 onChange 函数。
    • @JohnnyQ 不受控制的组件不需要onChange。通常,使用ref 提取值。
    • 太棒了,值设置和onKeyUp/onKeyPress等其他键有一个错误,所以如果你在某些情况下需要onKeyUp事件,你应该在同一个函数上设置onChange,否则value 属性不会被更新。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      问题就在这里:

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

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

      你想绑定到 'this',这样 changeTo 就会在 THIS 对象中设置状态。

      试试这个

      <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/

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

      【讨论】:

        【解决方案6】:

        使用条件渲染,组件会加载正确的初始值。这个模块中的内容:

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

        【讨论】:

          【解决方案7】:

          与上面 Sia 的出色回答相关:https://stackoverflow.com/a/41962233/4142459

          就我而言,我有几种方法可以更新表单:

          1. 用户可以在表单字段中输入值
          2. 一个 API 请求允许用户从以前的版本恢复
          3. 用户可以导航到填写好的表单(使用 URL 的 queryParams)
          4. 清除表单域。
          5. 等更多方式允许所有字段或仅通过用户操作或 websocket 进行单个更改。

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

          1. 在表单的顶层或表单的父元素上提供手动控制的 key 道具(只要它位于 DOM 树中的输入上方。
          2. 当用户键入 key 时,不需要进行更新。
          3. 我将key 设为简单的formHistoricalVersion,并且由于发生了与表单字段值交互的用户键入/选择/等外部的某些更新,因此我增加了 formHistoricalVersion。
          4. 这确保表单的状态无论是通过用户操作还是通过 API 请求都是同步的——我可以完全控制它。

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

          1. 在发出 API 请求时,使整个表单消失(将更改加载到加载微调器而不是表单时)。对性能和 clearForm 的不利之处在于这样做有点疯狂,但可以使用 setImmediate 在首次清除表单时将表单转换为加载微调器,然后在 setImmediate 中将 isLoading 设置回 false。李>
          2. 在每个输入上添加 key:效果非常好,但是每当用户输入时它都会出现奇怪的提示,所以我不得不删除它。
          3. 为表单 (field.id) 设置一个静态键(如上述答案所建议)并未涵盖我拥有的所有用例。

          总之,用 react/redux 设置表单的键很容易,我只需要添加相当于:

          return {
            ...state,
            formFieldState: payload.formFields,
            historicalFormVersion: state.historicalFormVersion + 1
          }
          

          这是必要的,因为我使用了一些 3rd 方库和我自己的数字输入,它们将值作为道具但使用值作为默认值:

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

          整体形式的近似 Redux:

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

          【讨论】:

            【解决方案8】:

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

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

            您只需要为您的元素添加一个 id 属性,以便它可以被定位。

            【讨论】:

            • 这打破了我认为的 React 哲学
            猜你喜欢
            • 2021-07-26
            • 1970-01-01
            • 2019-08-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-07-20
            相关资源
            最近更新 更多