How to change input value in redux
There are uncontrolled
(not set value) and controlled
(set value) input in reactjs.
controlled
not allow user input, but uncontrolled
does.
Solution:
- Need use
uncontrolled input
(no value attribute). - Select input element and set the value when
currentPath
change.
Bad way:
code:
export default class PathForm extends Component {
changeCurrentPath(path) {
const pathInput = document.querySelector('.current-path-input')
if (pathInput){
pathInput.value = path
this.lastPath = path
}
}
render() {
const { currentPath, handleSubmit } = this.props;
console.log('PathFormPathFormPathForm', this.props)
this.changeCurrentPath(currentPath)
return (
<div className="path-box">
<form onSubmit={handleSubmit}>
<div>
<input type="text" className="current-path-input" placeholder="input path" />
</div>
<button className="go-btn" type="submit">Go</button>
</form>
</div>
);
}
}
Good way:
use componentWillReceiveProps
to set props and rel
to select element
1.use form submit
export default class PathForm extends Component {
constructor(props) {
super(props)
// can not find `this` if not bind
this.handleSubmit = this.handleSubmit.bind(this)
}
componentWillReceiveProps(nextProps) {
if (nextProps.currentPath !== this.props.currentPath) {
this.setInputValue(nextProps.currentPath)
}
}
getInputValue() {
return this.refs.pathInput.value
}
setInputValue(val) {
this.refs.pathInput.value = val
}
handleSubmit(e){
e.preventDefault()
this.props.handleSubmit(this.getInputValue())
}
render() {
return (
<div className="path-box">
<form onSubmit={this.handleSubmit}>
<input className="current-path-input"
defaultValue={this.props.currentPath}
ref="pathInput" />
<button className="waves-effect waves-light btn" type="submit">Go</button>
</form>
</div>
);
}
}
2.use button click
export default class PathForm extends Component {
constructor(props) {
super(props)
// can not find `this` if not bind
this.handleGoClick = this.handleGoClick.bind(this)
this.handleKeyUp = this.handleKeyUp.bind(this)
}
componentWillReceiveProps(nextProps) {
if (nextProps.currentPath !== this.props.currentPath) {
this.setInputValue(nextProps.currentPath)
}
}
getInputValue() {
return this.refs.pathInput.value
}
setInputValue(val) {
this.refs.pathInput.value = val
}
handleKeyUp(e) {
if (e.keyCode === 13) {
this.handleGoClick()
}
}
handleGoClick(e) {
e.preventDefault()
this.props.handleSubmit(this.getInputValue())
}
render() {
return (
<div className="path-box">
<form >
<input className="current-path-input"
defaultValue={this.props.currentPath}
onKeyUp={this.handleKeyUp}
ref="pathInput" />
<button className="waves-effect waves-light btn" type="submit" onClick={this.handleGoClick}>Go</button>
</form>
</div>
);
}
}
Comments
-
Mithril almost 2 years
I am making a file manager app based on react-redux, and I meet problem with
input
.For example, my code:
PathForm.js:
export default class PathForm extends Component { render() { const { currentPath, handleSubmit } = this.props; console.log('PathFormPathFormPathForm', this.props) return ( <div className="path-box"> <form onSubmit={handleSubmit}> <div> <input type="text" className="current-path-input" placeholder="input path" value={currentPath} /> </div> <button className="go-btn" type="submit">Go</button> </form> </div> ); } }
Explorer.js:
class Explorer extends Component { goPath(e) { e.preventDefault() // fake function here, because I have to solve the input problem first console.log('PathForm goPath:',this.props) let {targetPath , actions} = this.props swal(targetPath) } render() { const { node, currentPath , actions} = this.props console.log('Explorer.render:',this.props) return ( <div className='explorer-container'> <PathForm currentPath={currentPath} handleSubmit={this.goPath.bind(this)}/> <FileListOperator /> <FileListView fileList={node && node.childNodes} actions ={actions} /> </div> ); } } function mapStateToProps(state, ownProps) { return { node: state.tree[state.tree.currentPath], currentPath: state.tree.currentPath }; } function mapDispatchToProps(dispatch) { console.log('mapDispatchToProps') return { actions: bindActionCreators(NodeActions, dispatch) }; } export default connect( mapStateToProps, mapDispatchToProps )(Explorer);
Feature I want:
I have a
PathForm
, it need show path from two way:-
user click a file path from left tree view,
Explorer
get this path ascurrentPath
, then pass toPathForm
, and showcurrentPath
in input -
user directly type a path to the
PathForm
's input,PathForm
callhandleSubmit
(Explorer's function) to change thecurrentPath
Additional:I want to keep
PathForm
as a stateless component
The problem:
- I'd like use
PathForm
as a stateless form, so I don't want connect it to store, but I need it change input bycurrentPath
. But if I setvalue={currentPath}
, user can not type anything else. - change to
<input type="text" onChange={this.changeValue} value={this.getValue()}/>
allow user type string in this input, but can not use propscurrentPath
passed byExplorer
- The only way I can imagine is connect this form to store which I don't want. I'd like
Explorer
to dispatch all actions and pass props.
Tried with some package
I found the input not act as my thought, so I tried the two popular package:
-
redux-form
It create a form need so much code, and official doc not say how to render this form with parent props, I try to pass
props
andhandleSubmit
to it, not work. After I see React + Redux - What's the best way to handle CRUD in a form component? and How to wire up redux-form bindings to the form's inputs I found I can't do that, it define some function overwrite mine, this behave is not good for me(I have to change the handlerSubmit function name, but it still not work), and it connect to the store. So I turn toformsy-react
-
formsy-react
It still need so much code, though it provide some
mixin
, but I still have to write a custom text input withchangeValue
function myself(changeValue
is no need in most situation when writing normalhtml jquery app
).Then I found the problem thatPathForm
can not use propscurrentPath
passed byExplorer
...
Probably Worked solution(but I don't tend to use):
connect
PathForm
to store, add another stateinputPathValue
for this input. UseinputPathValue
interact withcurrentPath
After above, I found use input/form is super in-convenient in react.... Does it mean I have to connect
PathForm
to stroe? Any other way to solve my problem? -