reactjs React -通过传递props更改输入defaultValue

jpfvwuh4  于 2023-10-17  发布在  React
关注(0)|答案(9)|浏览(118)

请考虑以下示例:

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

我想把值作为dumb输入组件的prop传递给defaultValue。但是它从不重新渲染它。

bkhjykvo

bkhjykvo1#

正如前面提到的,defaultValue只在初始加载表单时设置。在此之后,它不会“自然”更新,因为意图只是设置初始默认值。
如果需要,可以通过向 Package 器组件传递key来解决这个问题,就像在FieldApp组件上一样,尽管在更实际的情况下,它可能是form组件。一个好的key应该是传递给表单的资源的唯一值--比如存储在数据库中的id。
在简化的情况下,您可以在Field render中执行以下操作:

<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和timestamp。

aij0ehis

aij0ehis2#

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

arknldoa3#

我相当肯定这与控制vs.不受控制的输入
如果我理解正确的话,由于<input>是Uncontrolled(没有定义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显示变化。

0tdrvxhp

0tdrvxhp4#

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

093gszye

093gszye5#

问题在这里:

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

我很好奇你为什么绑定到null。
你想绑定到'this',这样changeTo将setState在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/
如果你使用的是火狐或Chrome,我也建议你使用React Dev工具,这样你就可以看到状态。消息没有改变:https://facebook.github.io/react/blog/2015/09/02/new-react-developer-tools.html

fiei3ece

fiei3ece6#

使用条件渲染,那么组件将加载正确的初始值。类似于这个模块:

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

k0pti3hp7#

与上面Sia的精彩回答相关:https://stackoverflow.com/a/41962233/4142459
对于我的情况,我有几种方法可以更新表单:
1.用户可以在表单域中输入值

  1. API请求允许用户从以前的版本恢复
    1.用户可以导航到已填写的表单(使用URL的queryParams)
    1.清除表单字段。
    1.等等,更多的方式允许所有的字段或只是一个单一的变化发生从用户操作或websockets。
    我发现确保表单的状态反映在其输入中的最简单方法确实是:
    1.在表单的顶层或表单的父元素上提供一个手动控制的key prop(只要它在DOM树中的输入之上)。
    1.当用户输入key更新时,不需要进行更新。
    1.我把key变成了一个简单的formHistoricalVersion,当用户输入/选择/等与表单字段的值进行交互时,我增加了formHistoricalVersion。
    1.这确保了表单的状态(无论是通过用户操作还是通过API请求)是同步的--我可以完全控制它。
    我尝试的其他解决方案:
    1.当发出API请求时,使整个表单消失(当加载时,更改为加载微调器而不是表单)。对性能和clearForm的缺点是这样做有点疯狂,但可以使用setImmediate在第一次清除表单时将其转换为加载微调器,然后在setImmediate中将isLoading设置回false
    1.在每个输入上添加key:这工作惊人,但它有一个奇怪的光点每当用户将输入,所以我不得不摆脱它。
    1.为表单(field.id)放置一个静态键(如上面的答案所建议的)并没有涵盖我所拥有的所有用例。
    总之,用react/redux设置表单的键很容易,我只需要添加以下内容:
return {
  ...state,
  formFieldState: payload.formFields,
  historicalFormVersion: state.historicalFormVersion + 1
}

这是必要的,因为我使用了一些第三方库和我自己的Numeric Input,它将value作为prop,但将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>
  )
}
i2byvkas

i2byvkas8#

有点古怪,但做的工作。

let cursorPos = e.target.selectionStart;
e.target.blur();
setTimeout(() => {
    e.target.setSelectionRange(cursorPos, cursorPos - 1);
    e.target.focus();
}, 50);
i1icjdpr

i1icjdpr9#

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

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

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

相关问题