I am trying to insert data in database using multiple components in reactjs. In my first component I have a Form like below (there is not Submit button in this component)
render() {
return (
<form>
<input type="text" name="name" placeholder="Name"/>
</form>
);
}
In second component I am calling that component with if else logic.
In third component I have the submit button like below
<Button
positive icon='checkmark'
labelPosition='right'
onClick={this.insertAddress}
content='Save'
/>
My main issue is using state. How can I use state effectively here ? How can I catch the input values of first component in third component to insert in database ?
You create a parent container. The parent container holds the state, all the methods and event handlers. All of those are binding to the parent.
You then pass the methods and parts of the state down to the children. When they children use them, they will be changing the parent. I created a simple sandbox to demonstrate. You don't need to pass the entire state down, just the parts needed by the children.
https://codesandbox.io/s/q335wnjoyj
Use the concept of Container component.
create a container component which will hold the state of all you child components. keep updating all state related to Data in here. and call save functionality from here.
class Parent extends React.Component{
constructor(props){
super(props);
this.state={
name:'',
email:'',
phone:''
}
this.handleFormChanges = this.handleFormChanges.bind(this)
this.handleSubmit = this.handleSubmit.bind(this);
this.reactToSomeChange = this.reactToSomeChange.bind(this)
}
handleFormChanges(ev){
// handle form and set appropriate state
}
handleFormChanges(ev){
// react to change and set state
}
handleSubmit(){
// update your data store db etc.
}
render(){
return(
<MyForm changes={this.handleFormChanges} />
<IfElse changes={this.reactToSomeChange} />
<Button submit={this.handleSubmit} />
)
}
}
// MyFrom component render function
render() {
return (
<form>
<input type="text" name="name" onChanges={this.props.changes} placeholder="Name"/>
</form>
);
// Button component render function
render(){
<button onClick={this.props.submit}>SUBMIT<Button>
}
Child components need not to call apis to save the data. it should be done from a single parent component that shares the same state in the child components.
Related
I have a page that has a number of forms on it. In an effort to try and keep the forms consistent, I have a main Form class component that is extended by all the other forms.
This parent Form component has the logic in it to add field validation, along with adding secure tokens before and after the form fields:
Parent Form
class Form extends React.Component {
constructor(props) {
super(props);
}
view(child) {
return (
<>
<form onSubmit={this.handleSubmit} className="form">
... // extra form fields
{child} // 'actual' form fields, passed from child
... // extra wrapper form fields
<button>Submit</button>
</form>
</>
);
}
}
export default Form;
Child Form
class LoginForm extends Form {
constructor(props) {
super(props);
this.state = {
data: {} ... form-field specific data
}
}
render() {
return this.view(
<>
<MyFormField name="field1" onChange={this.handleChange} onBlur={this.handleBlur} field={this.state.data.field1} />
<MyFormField name="field2" onChange={this.handleChange} onBlur={this.handleBlur} field={this.state.data.field2} />
<MyFormField name="field3" onChange={this.handleChange} onBlur={this.handleBlur} field={this.state.data.field3} />
</>
);
}
}
export default LoginForm;
The LoginForm (child) extends the parent Form, and in its render method, calls the view method of the parent. This effectively will render the pieces passed over with the parent handling validation and such.
The problem it is facing, is that when an update is performed on one of the fields, it is not updating the child (LoginForm) - so any field validation errors are not displaying, and so forth.
Page
class MyPageComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<>
<div className="my-page">
<h2>header</h2>
<LoginForm /> // including LoginForm
</div>
</>
);
}
export default MyPageComponent;
The MyPageComponent will create the layout, and then embed the form in the page wherever it may be. The embedded form, in this case - LoginForm will contain all the handlers for the validation, submission, state and all that of the form.
Is this an anti-pattern? I have not found anything so far to suggest so, but it is frustrating - and I cannot help but wonder if there is a better way to do this. The only part that strikes me as somewhat unconventional, is that the child's render method calls the parent classes view method.
My goal in all this is just to create a consistent handler for all the forms on the site that can easily be reused.
How do I get the child/LoginForm to update when it is updated in the parent Form? Is there a better way to do this?
Edit
Updates to the state.data.field elements are the updates that I am referring to. These are updated by running this.setState(newState) on the Form component. Usually, a state change would trigger a render update?
I am new in reactjs and learning bit and pieces. I am facing an issue. The scenario is like. I have a functional component as a parent. It has a child component as a class component. I would like to set or reset the child component's state on parent's button click. Or is there any way to call the child component's any method from the parent component. I tried as
// this call from a functional component.
<PhotoPreviewUploaend setSelectedFile={setSelectedFile} ref={setImagePreviewUrl} />
Later after a button click does this:-
setImagePreviewUrl('');
I read ref attribute allows access to the component. I tried this ref between 2 class component both parent and child is class components and it works as expected. But when did the same from a functional component it has no effect at all. How can I do it?
You are not embracing react one-way data flow by using refs like that; it might not behave the way you expect;
You should pass parent state handler logic function to the child component,
then child component call it with proper value; as the result your parent state will be updated and you have nice and clean one way data flow; you can use this in any kind of component, since you don't mess with this bindings in functional components;
This example demonstrates it in action:
function App() {
// Define your state
const [someState, setSomeState] = useState(0);
return (
<div className="container">
<Child parentCallback={setSomeState} />
</div>
);
}
class Child extends Component {
render(){
return(
<div>
<button
onClick={() => this.props.parentCallback(/*someValue*/)}
>
click me!
</button>
</div>
)
}
}
Setup: I have set up a two react components in a parent child relationship. The parent has a state that can be changed by press of a button on parent itself.
Expected behaviour: In the child, I have an input field and I want the state to change to the value I send in the input field on the press of the submit button. I have set up the parent and the child as follows:
What I have tried: I going through this answer and this youtube video but I guess I am not smart enough to make sense of it.
This is what my code looks like
Parent:
class App extends Component {
state = {
value:"someValue"
};
changeValue = (value) => {
this.setState({
value
})
}
render() {
return (
<div>
<p>this is the value from state: {this.state.value}</p>
<button onClick={()=>this.changeValue("valueFromParentComponent")}>Press to change value from parent component</button>
<br/><br/>
<Child getChildInputOnSubmit={()=>this.changeValue()} />
</div>
);
}
}
And this is what the child looks like
Child:
class Child extends Component {
state = {
}
sendChildData = (childInputValue) => {
console.group("This is the data from the input of the child component")
console.log("==============")
console.log(childInputValue)
console.log("==============")
}
render() {
return (
<div>
This is the child component
<br /><br />
<form>
<input type="text" placeholder="Some placeholder"></input>
<button onSubmit={this.sendChildData()} type="submit">Send child's input to parent</button>
</form>
</div>);
}
}
The React behaviour encourages to implement an inverse data flow inside a component hierarchy. Meaning that the child components can receive parent methods through props, this methods will work as callbacks, allowing to receive data, trigger behaviours, update his state and more.
I attach a StackBlitz example, showing how this concept would work in your setup https://stackblitz.com/edit/react-jsv5jo
Edit: Here a few extra tips applied on the example:
To work with inputs on React, a common setup consists on listen the onChange event to receive new data and update the component state. Then, this state is used in the value attribute to update the input content on DOM.
Listen the onSubmit event on the form tag instead on submit button, and remember to add some logic to avoid reloading.
Another good practice on React components is initialize your state object inside the Constructor (In case to be working with a Class Component) and write methods to avoid bloat the render one (Be sure to bind the extra methods on your constructor to avoid invocation problems)
Callbacks are used to pass data from Child component to Parent component in React.
We wright function in Parent component that will receive value and pass this function to child component through Props.
class Parent extends Component {
state = {
value: 'someValue'
};
changeValue = value => {
this.setState({
value
});
};
render() {
return (
<div>
<p>this is the value from state: {this.state.value}</p>
<button onClick={() => this.changeValue('valueFromParentComponent')}>
Press to change value from parent component
</button>
<br></br>
<Child getChildInputOnSubmit={this.changeValue} />
</div>
);
}
}
Now in Child component we call Parents function that we passed in props and send value.
class Child extends Component {
constructor(props) {
super(props);
this.state = {
Childvalue: ''
};
}
handleChange = event => {
event.preventDefault();
this.setState({ Childvalue: event.target.value });
};
sendToParent = () => {
//here calling Parents changeValue
this.props.getChildInputOnSubmit(this.state.Childvalue);
};
render() {
return (
<div>
This is the child Component
<br></br>
<form action='#' onSubmit={this.sendToParent}>
<input
type='text'
placeholder='Some placeholder'
value={this.state.Childvalue}
onChange={this.handleChange}
></input>
<button type='submit'>Send child's input to parent</button>
</form>
</div>
);
}
}
I have some text. When you click on that element a modal pops up that lets you edit that text. The easiest way to make this work is to call setState on the child to initialise the text.
The other way, although more awkward, is to create an initial text property and make the child set it's text based on this.
Is there anything wrong with directly calling setState on the child or should I use the second method?
Although it is recommended to keep the data of your react application "up" in the react dom (see more here https://reactjs.org/docs/lifting-state-up.html), I don't see anything wrong with the first aproach you mentioned.
If you have to store data that is very specific of a child I don't see anything wrong in keep that information in the child's state.
It seems that your modal doesn't need to have its own state, in which case you should use a stateless React component.
This is one way of passing the data around your app in the React way.
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
initialText: "hello",
}
this.saveChildState = this.saveChildState.bind(this);
}
saveChildState(input) {
console.log(input);
// handle the input returned from child
}
render() {
return (
<div>
<ChildComponent
initialText={this.state.initialText}
save={this.saveChildState}
/>
</div>
);
}
}
function ChildComponent(props) {
return (
<div>
<input id="textInput" type="text" defaultValue={props.initialText}>
</input>
<button onClick={() => props.save(document.getElementById('textInput').value)}>
Save
</button>
</div>
)
}
Maybe I am misinterpreting your question, but I think it would make the most sense to keep the modal text always ready in your state. When you decide to show your modal, the text can just be passed into the modal.
class Test extends Component {
constructor() {
this.state = {
modalText: 'default text',
showModal: false
}
}
//Include some method to change the modal text
showModal() {
this.setState({showModal: true})
}
render(
return (
<div>
<button onClick={() => this.showModal()}>
Show Modal
</button>
{ this.state.showModal ? <Modal text={this.state.modalText}/> : null }
</div>
)
)
}
I'm trying to click on a sort icon that will trigger to change the order of a list.
To make it more simpler, let's say you have a button and another button and they are on separate divs from each other.
<div>
//Button 1
<button onclick={"some_click_handler"}>
</div>
<div>
//Button 2
<button>
{this.state.someToggle ? true : false}
</button>
</div>
Create a component which passes a callback to the button, this callback will update the state of the container which will in turn set the props of the list. This is very common in React and is the basis of how the compositional pattern works. If you need to share data between two components just put them in a container and lift the state to the parent component. These components are usually called containers and there is a bunch of documentation on it.
This is a good starting point: https://reactjs.org/docs/lifting-state-up.html
Something like this...
class Container extends React.Component {
constructor(props) {
super(props);
// Don't forget to bind the handler to the correct context
this.handleClick = this.handleClick.bind(this);
}
handleClick(sort) {
this.setState({sort: sort});
}
render() {
return (
<Button handleClick={this.handleClick} />
<List sort={this.state.sort} />
)
}
}