繁体   English   中英

React - 通过传递道具更改输入默认值

[英]React - change input defaultValue by passing props

考虑这个例子:

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作为哑输入组件的道具。 但是它永远不会重新渲染它。

正如前面提到的答案, 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 加时间戳。

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

我相当肯定这与Controlled vs. Uncontrolled 输入有关

如果我理解正确,因为您的<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>
          );
      }
  });

这是一个显示更改的plunker

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

问题在这里:

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

使用条件渲染,然后组件将加载正确的初始值。 在这个模块中的东西:

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的形式转化到装载微调时,他们首先清除它,然后设置isLoadingfalse的setImmediate。
  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>
  )
}

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM