Reputation: 1719
So I have a component A (extends React.component) and it is wrapped with a higher order component B.
In component B's methods, I need to setState for A, or call a function in A (so that it can do the setState) - how is this generally done?
I can paste actual code here, but I thought it may complicate matters if there are standard ways of handling this situation.
Edit: here's the code - isOpen needs to change for the Modal to close, and it needs to change in handleSubmit....
import React from 'react';
import Modal from 'react-modal';
import { withFormik, Form, Field } from 'formik';
import Yup from 'yup';
// first part of Formik integration
const formikEnhancer = withFormik({
mapPropsToValues(props) {
return {
personName: props.email || '',
personSurname: props.surname || '',
personCongregation: props.congregation || ''
}
},
validationSchema: Yup.object().shape({
personName: Yup.string().required().min(1),
personSurname: Yup.string().required().min(2),
personCongregation: Yup.string().required().min(8)
}),
handleSubmit(values, {props, resetForm, setErrors, setSubmitting}) {
submitNewPerson(values, {resetForm, setErrors, setSubmitting});
props.testCall;
}
});
function submitNewPerson(v, {resetForm, setErrors, setSubmitting}) {
//e.preventDefault();
congregations = [];
congregations.push(v.personCongregation);
const peep = {
name: v.personName,
surname: v.personSurname,
congregations: congregations//,
//startDate: Number(e.target.componentStartDate.value),
//endDate: Number(e.target.componentEndDate.value)
};
// do the db insert here and check for errors
setSubmitting(false);
});
};
class AddPerson extends React.Component {
constructor(props) {
super(props);
this.state = {
error: undefined,
isOpen: false
}
}
componentWillMount() {
Modal.setAppElement('body');
}
renderCong() {
// this just maps out a list of select options
}
render() {
return (
<div>
<button className="button" onClick={()=> this.setState({isOpen:true, error:undefined})}>+ Add Person</button>
<Modal isOpen={this.state.isOpen} contentLabel="Add Person"
className = "boxed-view__box" overlayClassName="boxed-view boxed-view--modal">
<Form className="boxed-view__form">
<div>
<Field type="text" name="personName" placeholder="Name" />
</div>
<div>
<Field type="text" name="personSurname" placeholder="Surname" />
</div>
<div>
<Field component="select" name="personCongregation" value={this.state.cong}>
<option key="0" value="">- Select Option -</option>
{this.renderCong()}
</Field>
</div>
<button disabled={this.props.isSubmitting} className="button">Add Person</button>
<button disabled={this.props.isSubmitting} type="button" className="button button--secondary" onClick={
()=> {
this.props.resetForm();
this.setState({isOpen:false});
}}>Cancel</button>
</Form>
</Modal>
</div>
)
};
};
Upvotes: 2
Views: 1106
Reputation: 1719
Figured it out - added my own onClick handler (instead of allowing Formik to call its handleSubmit method) - my handler then calls Formik's handleSubmit and then changes state depending on return value
Upvotes: 0
Reputation: 49
Generally you send props to the component and then you handle those props with a function, that in this case sets the state with stuff, example:
class B extends React.Component{
render(){
<A toUpdateState={this.state.valueB} />
}
}
class A extends React.Component{
updateState(){
this.setState({
...this.state,
valueA: this.props.toUpdateState
})
}
render(){...}
}
If you trigger the state in the B component the A component will receive the info.
There are other ways to do this but without the code its hard to give you a diferent solution.
Upvotes: 0
Reputation: 5188
Unless you are in control of component B, this isn't really possible. Some popular HOCs (like connect
in react-redux) have a mechanism that allows you to expose the wrapped component A, but this isn't true in general.
It's generally better not to do this at all. If the state of a component needs to be changed from the outside, it should be passed in as a prop and the "source of truth" should be your model or viewmodel. If you're using something like redux, try moving your component state into redux state, and instead of calling setState, use a redux action/reducer combo to update it.
Another way is to move the state up one level so that it's passed in as a prop from another component (the parent), and then have the logic in that parent, although this is much less flexible.
Upvotes: 4