Suppose i have Component A that contains an input field. A second Component B contains a submit button. The two components aren't linked directly (e.g they are 2 leaf in a 2-depth tree)
On Submit i need to retrieve input value, how to resolve this in a react + redux environment?
The most obvious solution that came to my mind was to bind React Component's refs to redux state, in this way the state has the reference to the input value (accessed through state.fieldName.input.value).
In the submit button Component (remember it has no direct relations with input component) the mapStateToProps return onClick prop that is a function that can access to the state and thus the input values and can do the "impure" job (e.g. db request)
So my code should be like this:
//components/TestForm.jsx
class TestForm extends Component {
render() {
return <FormInput
ref={(ref) => this.props.registerFormField(ref)}
value=...
...
/>
}
}
//redux/actions/index.js
const registerFormField = (field) => {
return {
type: ActionTypes.REGISTER_FORM_FIELD,
field: field
}
}
//redux/reducers/index.js
const rootReducer = (state = {}, action) => {
switch (action.type) {
case ActionTypes.REGISTER_FORM_FIELD:
var newState = {...state};
newState[action.field.input.name] = action.field.input;
return newState
default:
return state
}
}
//containers/SubmitButton.js
const mapStateToProps = (state, ownProps) => {
return {
text: "Submit",
onClick: () => {
//do your impure job with state.fieldName.value
}
}
}
const SubmitButton = connect(
mapStateToProps,
mapDispatchToProps
)(FormSubmitButton)
//components/FormSubmitButton.jsx
class FormSubmitButton extends Component {
render() {
return <button
onClick={this.props.onClick}
>
{this.props.text}
</button>
}
}
I briefly read redux-form docs and it seems it can't bind two non-related from components as described above (maybe i'm wrong ;) )
Is there any other right/elegant solution to solve this problem?
There is no need to use
ref
s in this case.The idiomatic approach would be to create your form fields as controlled components by supplying the
value
property. This could either be supplied from the global state (mapped in yourmapStateToProps
), or from the state of the common parent component.You will also need to listen to changes of the inputs. For that, supply a handler to the
onChange
prop of yourinput
. This handler should then change the form data, either in your redux store or in the component state, depending on which approach you take.This way, it does not matter where in your react application you place your submit button etc., as long as it has access to the form data.
For a working example of your use case, have a look at this JSBin. This demonstrates how you could separate your form into multiple components and keep the input values in your redux store without relying on
ref
s.