[英]React - change input defaultValue by passing props
Consider this example:考虑这个例子:
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')
);
I want to pass value into defaultValue
as prop of dumb input component.我想将值传递给
defaultValue
作为哑输入组件的道具。 However it never re-renders it.但是它永远不会重新渲染它。
As a previous answer mentioned, defaultValue
only gets set on initial load for a form.正如前面提到的答案,
defaultValue
仅在表单的初始加载时设置。 After that, it won't get "naturally" updated because the intent was only to set an initial default value.之后,它不会“自然”更新,因为目的只是设置初始默认值。
You can get around this if you need to by passing a key
to the wrapper component, like on your Field
or App
component, though in more practical circumstances, it would probably be a form
component.如果需要将
key
传递给包装器组件(例如在Field
或App
组件上),您可以解决此问题,但在更实际的情况下,它可能是form
组件。 A good key
would be a unique value for the resource being passed to the form - like the id stored in the database, for example.一个好的
key
应该是传递给表单的资源的唯一值 - 例如存储在数据库中的 id。
In your simplified case, you could do this in your Field render:在您的简化情况下,您可以在 Field 渲染中执行此操作:
<div key={this.props.value}>
<input type="text" defaultValue={this.props.value || ''} />
</div>
In a more complex form case, something like this might get what you want if for example, your onSubmit action submitted to an API but stayed on the same page:在更复杂的表单案例中,例如,如果您的 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
}
When using uncontrolled form inputs, we generally don't care about the values until after they are submitted, so that's why it's more ideal to only force a re-render when you really want to update the defaultValues (after submit, not on every change of the individual input).当使用不受控制的表单输入时,我们通常在提交之后才关心这些值,所以这就是为什么只在您真正想要更新 defaultValues 时才强制重新渲染更为理想(提交之后,而不是每次更改时)个人输入)。
If you're also editing the same form and fear the API response could come back with different values, you could provide a combined key of something like id plus timestamp.如果您还在编辑相同的表单并且担心 API 响应可能会返回不同的值,您可以提供一个组合键,如 id 加时间戳。
defaultValue only works for the initial load. defaultValue仅适用于初始加载。 After that, it won't get updated.
在那之后,它不会得到更新。 You need to maintain the state for you Field component:
您需要为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>
);
}
});
I'm fairly certain this has to do with Controlled vs. Uncontrolled inputs .我相当肯定这与Controlled vs. Uncontrolled 输入有关。
If I understand correctly, since your <input>
is Uncontrolled (doesn't define a value
attribute), then the value will always resolve to the value that it is initialized with.如果我理解正确,因为您的
<input>
是不受控制的(未定义value
属性),那么该值将始终解析为初始化时使用的值。 In this case Hello!
在这种情况下
Hello!
. .
In order to overcome this issue, you can add a value
attribute and set it during the onChange
:为了克服这个问题,您可以添加一个
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 showing the change.这是一个显示更改的plunker 。
您可以有条件地进行输入,然后每次要强制更新defaultValue
您只需要卸载输入,然后立即再次渲染它。
The issue is here:问题在这里:
onClick={this.changeTo.bind(null, 'Whyyyy?')}
I'm curious why you bind to null.我很好奇你为什么绑定到 null。
You want to bind to 'this', so that changeTo will setState in THIS object.您想绑定到“this”,以便 changeTo 将在 THIS 对象中设置状态。
Try this尝试这个
<button onClick={this.changeTo.bind(this, 'Whyyyy?')}>Change to "Whyyyy?"</button>
<button onClick={this.changeTo.bind(this, void 0)}>Change to undefined</button>
In Javascript, when a function is called, its called in the scope where it was called from, not where it was written (I know, seems counter intuitive).在 Javascript 中,当一个函数被调用时,它在它被调用的范围内被调用,而不是在它被写入的地方(我知道,这似乎违反直觉)。 To ensure it is called in the context you write it, you need to '.bind(this)'.
为了确保在你编写它的上下文中调用它,你需要'.bind(this)'。
To learn more about binding and function scope, there are lots of online tutes, (some much better than others) - you might like this one: http://ryanmorr.com/understanding-scope-and-context-in-javascript/要了解有关绑定和函数作用域的更多信息,有很多在线教程(有些比其他教程要好得多)-您可能会喜欢这个: http : //ryanmorr.com/understanding-scope-and-context-in-javascript/
I also recommend using the React Dev tools if you are using firefox or chrome, this way you would have been able to see that state.message was not changing: https://facebook.github.io/react/blog/2015/09/02/new-react-developer-tools.html如果您使用的是 firefox 或 chrome,我还建议您使用 React Dev 工具,这样您就可以看到 state.message 没有改变: https ://facebook.github.io/react/blog/2015/09 /02/new-react-developer-tools.html
Use conditional rendering, then the component will load correct initial value.使用条件渲染,然后组件将加载正确的初始值。 Something like in this module:
在这个模块中的东西:
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;
}
}
}
Related to Sia's excellent answer above: https://stackoverflow.com/a/41962233/4142459 .与以上 Sia 的出色回答相关: https : //stackoverflow.com/a/41962233/4142459 。
For my case I had a few ways in which a form could be updated:就我而言,我有几种方法可以更新表单:
I found that the easiest way to make sure the state of the form is reflected in its inputs is indeed:我发现确保表单状态反映在其输入中的最简单方法确实是:
key
prop on the top level of the form or parent element to the form (as long as it is above the inputs in the DOM tree.key
prop(只要它位于 DOM 树中的输入之上。key
update does not need to happen.key
,不需要发生更新。key
be a simple formHistoricalVersion
and as certain updates external to a user typing/selecting/etc interacting with the form field's values happened I incremented the formHistoricalVersion.key
为一个简单的formHistoricalVersion
并且当用户键入/选择/等与表单字段的值交互时发生某些外部更新时,我增加了 formHistoricalVersion。 Other solutions I tried:我尝试过的其他解决方案:
setImmediate
to convert the form to a loading spinner when they first clear it, then setting isLoading
back to false
in the setImmediate.setImmediate
的形式转化到装载微调时,他们首先清除它,然后设置isLoading
回false
的setImmediate。key
on each input: this worked amazingly, but it had a weird blip whenever users would type so I had to get rid of it.key
:这非常有效,但是每当用户输入时它都会有一个奇怪的光点,所以我不得不摆脱它。field.id
) (as suggested by above answer) didn't cover all the use cases I had.field.id
)放置一个静态键(如上面的答案所建议的)并没有涵盖我拥有的所有用例。 In conclusion, it worked pretty easily to set the key of the form with react/redux, I just would add the equivalent of:总之,使用 react/redux 设置表单的键非常容易,我只需添加以下内容:
return {
...state,
formFieldState: payload.formFields,
historicalFormVersion: state.historicalFormVersion + 1
}
This was necessary because I was using some 3rd party libraries and my own Numeric Input that took in value as a prop but used value as a defaultValue:这是必要的,因为我使用了一些 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)}
/>
)
Approximate Redux of overall Form:整体表格的近似 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>
)
}
I also face this problem, what I did was to manually update the input value when the props has change.我也面临这个问题,我所做的是在道具发生变化时手动更新输入值。 Add this to your Field react class:
将此添加到您的 Field 反应类:
componentWillReceiveProps(nextProps){
if(nextProps.value != this.props.value) {
document.getElementById(<element_id>).value = nextProps.value
}
}
You just need to add an id attribute to your element so that it can be located.您只需要向您的元素添加一个 id 属性,以便可以定位它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.