React handle state update - reactjs

I'm using the react to build some input forms.
While all children inputs have and their own states to store values I have no idea how to process the to a parent.
Here's example:
class FormComponent extends Component {
constructor(props) {
super(props);
this.state = {
title: null,
someAmount: null
}
}
render() {
let me = this;
return (
<div>
<TextField
value={me.state.title}
onChange={(proxy, value) => {
me.setState({title: value})
me.hanleChnage();
}
}
/>
<TextField
value={Number.parseFloat(me.state.someAmount)}
onChange={(proxy, value) => {
if (!isNaN(Number.parseFloat(value))) {
me.setState({someAmount: value})
me.hanleChnage();
}
}
}
/>
</div>
)
}
handleChange() {
//Calling the parent
//State here is outdated
this.props.onUpdate && this.props.onUpdate(this.state);
}
}
export default FormComponent;
Or where I can find some example of usage of compex forms with much inputs in react.
Thanks!

Sounds like you need to consider moving some of your state into the parent components. The React docs have a good article about this.
To summarize, you can pass your hanleChnage(); function as a prop to your child components if you declare the function in your parent.
function handleChange() { //do something... }
...
<ChildComponent parentOnChange={this.handleChange.bind(this) />
As your components grow in complexity, you might consider using Redux for state management, thus serving as a single source for all state in your application.

Set a child property, (e.g. callParentProperty) to reference a function in the parent component (e.g. parentFunction).
class ParentComponent extends Component{
parentFunction(parameter) {
console.log("This is the form value");
console.log(parameter);
}
render() {
return <FormComponent callParentFunctionProperty={this.parentFunction.bind(this)} />
}
}
class FormComponent extends Component {
...
handleChange() {
...
let formValue = this.state.someAmount;
this.props.callParentFunctionProperty(formValue);
}
}

Related

Render child component in parent after re-rendering sibling component

I have a parent component housing two children components(AddPersonForm and PeopleList). When I submit a name via the AddPersonForm, I expect it to be rendered in the PeopleList component, but it doesn't.
Here is my AddPersonForm:
class AddPersonForm extends React.Component {
state = {
person: ""
}
handleChange = (e) => this.setState({person: e.target.value});
handleSubmit = (e) => {
if(this.state.person != '') {
this.props.parentMethod(this.state.person);
this.setState({person: ""});
}
e.preventDefault();
}
render() {
return (
<form onSubmit={this. handleSubmit}>
<input type="text" placeholder="Add new contact" onChange={this.handleChange} value={this.state.person} />
<button type="submit">Add</button>
</form>
);
}
My PeopleList component:
class PeopleList extends React.Component {
constructor(props) {
super(props);
const arr = this.props.data;
this.state = {
listItems: arr.map((val, index) => <li key={index}>{val}</li> );
}
}
render() {
return <ul>{this.state.listItems}</ul>;
}
}
Now the parent component, ContactManager:
class ContactManager extends React.Component {
state = {
contacts: this.props.data
}
addPerson = (name) => {
this.setState({contacts: [... this.state.contacts, name]});
render() {
return (
<div>
<AddPersonForm parentMethod={this. addPerson}×/>
<PeopleList data={this.state.contacts} />
</div>
);
Please what I'm I doing wrong, or not doing?
The issue is in your PeopleList component. The state object which renders your list is created in the constructor when the component mounts, but you have no way of updating it when it recieves new values. It will always give you the initial value.
You could introduce a lifecycle method, componentDidUpdate, which would allow you to compare the previous props to the new props when they arrive, and update the state accordingly. I would recommend you not do this for two reasons:
Storing props directly in a components state is not good practice. You are just creating a copy of the state in the component above and that creates opportunities for confusion and stale values when one of them updates. Ideally, each piece of data should live in only one place.
If all PeopleList is doing is rendering your data, then it doesn't need any state at all. It can act as a display component that maps your props in place and doesn't have to worry about updating itself or managing its own data. This would actually make it a good candidate for conversion into a functional component.
class PeopleList extends React.Component {
render() {
return (
<ul>
{this.props.data.map((val, index) => (
<li key={index}>{val}</li>
))}
</ul>
);
}
}
You are initializing PeopleList with props when its created and mounted but then you are not using new values of props for updating it.
To fix your issue use current value of prop when rendering:
class PeopleList extends React.Component {
render() {
return <ul>{ this.props.data.map((val, index) => <li key={index}>{val}</li>) }</ul>;
}
}

Is it safe to pass in React component class instance to child component to access to the parent's variables and methods?

I am trying to get data from parent component. I know that I can pass in functions or variables to the child component but its looks cleaner to just pass in this to child component to access to its parent functions or variables.
class Parent extends Component {
state = {
_id: 123456789
}
foo = (val) => {
this.setState({_id:val})
}
render() {
return(
<Child parentInstance={this} />
)
}
}
class Child extends Component {
update = (e) => {
this.props.parentInstance.foo(e.target.value);
}
render() {
return(
<p>{this.props.parentInstance.state._id}</p>
<input onChange={this.update} />
)
}
}
If you find yourself passing this down (as I did many times when learning React!), you’ll find it useful to re-read Thinking in React.
In this instance, you should be passing the ID down as a prop. When the state changes, React knows that it’s used to calculate that prop and so will re-render the child component.
As for the callback, that’s best handled as an individual function. If you find yourself passing many callbacks around in your app, you may want to look into using a more complex state management system than just Reacts internal state values.
class Parent extends Component {
state = {
_id: 123456789
}
foo = (val) => {
this.setState({ _id: val })
}
render() {
return(
<Child parentId={this.state._id} onChange={this.foo} />
)
}
}
class Child extends Component {
update = (e) => {
this.props.onChange(e.target.value);
}
render() {
return(
<p>{this.props.parentId}</p>
<input onChange={this.update} />
)
}
}
It is more typical to pass properties and callbacks as props, not the instance itself.
i.e. <Child parentId={this.state._id} onUpdate={this.foo} />

ReactJS render element by ref

I am trying to render an parent-component which has two children. The rendering of the children will switch, so one time there will be only the first child rendered, another time it will be the last and finally it will switch back to the first child (which then should contain all the values shown before).
I thought this would be simple but it turned out that it is not.
Now to the problem: Whenever the method switchContainer is called, it will switch the container and render the other. However all member-variables, props and states are getting lost and it basically reinstanciated the child-component from scratch.
Is there a way to save the child-components "as-is" and once it is getting re-rendered, it will hold all the member-variables, props and states again?
I know that you can send props and states to the element like this:
<Child props={<data>} states={<data>}>
but this doesn't solve the issue with the missing membervariables and in my opinion it isn't a smooth solution.
My attempt so far is (this is just a mockup):
class Parent extends React.Component<any,any> {
private firstContainer:any;
private secondContainer:any;
private currentContainer:any;
constructor(props:any) {
super(props);
this.firstContainer = <Child>;
this.secondContainer = <Child>;
}
public render() {
return (
<div>
{this.currentContainer}
</div>
);
}
public switchContainer() {
if(this.currentContainer === this.firstContainer) {
this.currentContainer = this.secondContainer;
}
else {
this.currentContainer = this.firstContainer;
}
this.forceUpdate();
}
}
class Child extends React.Component<any,any> {
private anyValue:string;
constructor(props) {
this.change = this.change.bind(this);
}
public render() {
return (
<input onChange={this.change} value={this.anyValue}/>
);
}
private change(e:any) {
this.anyValue = e.target.value;
}
}
You can try maintaining a state and update children in render instead of saving child as firstContainer and secondContainer
class Parent extends React.Component<any, any> {
constructor(props) {
super(props);
this.state = {
firstChild: true
};
}
public render() {
const { firstChild } = this.state;
<div>
<Child1 show={firstChild}/>
<Child2 show={!firstChild} />
</div>
}
public switchContainer() {
this.setState(({ firstChild }) => ({ firstChild: !firstChild }));
};
}
And in child component, handle show to showContent otherwise render null. If you want to retain state, you should not unmount the component.

React - How to pass `ref` from child to parent component?

I have a parent and a child component, I want to access the ref of an element which is in the child component, in my parent component. Can I pass it with props?
// Child Component (Dumb):
export default props =>
<input type='number' ref='element' />
// Parent Component (Smart):
class Parent extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const node = this.refs.element; // undefined
}
render() {
return <Dumb { ...this.props }/>
}
}
You could use the callback syntax for refs:
// Dumb:
export default props =>
<input type='number' ref={props.setRef} />
// Smart:
class Parent extends Component {
constructor(props) {
super(props);
}
setRef(ref) {
this.inputRef = ref;
}
render(){
return <Dumb {...this.props} setRef={this.setRef} />
}
}
With react^16.0.0 you would use React.createRef(). Using #Timo's answer, it would look like this:
// Dumb:
export default props =>
<input type='number' ref={props.setRef} />
// Smart:
class Parent extends Component {
constructor(props) {
super(props);
this.ref1 = React.createRef()
}
render(){
return <Dumb {...this.props} setRef={this.ref1} />
}
}
As per DOC:
You may not use the ref attribute on functional components because
they don't have instances. You should convert the component to a class
if you need a ref to it, just like you do when you need lifecycle
methods or state.
So i think, if you want to use the ref, you need to use class.
Check this: https://github.com/facebook/react/issues/4936
If you need dynamic refs, because you have an array or something, like I did. Here is what I came up with after reading the answers above.
Also this assumes the myList is an array of objects with a key property. Anyways you get it.
Also this solution works without any issues from TypeScript as well.
const Child = props => <input ref={refElem => setRef(props.someKey, refElem)} />
class Parent extends Component {
setRef = (key, ref) => {
this[key] = ref; // Once this function fires, I know about my child :)
};
render(){
return (
{myList.map(listItem => <Child someKey={listItem.key} setRef={this.setRef} />)}
)
}
}
Anyways hope this helps someone.

How to share a property with React components?

I'm new to React and I have a question about sharing properties from one component to another. For example, I want a parent component that has a "visible" function that I can pass to other child components.
Example:
CustomInput visible="true";
CustomDropDown visible="false"
I'd like to know the best way to do this, respecting good practices. Thank you for your help!
Real simple. You can pass methods as props. Suppose you have a parent, or Higher Order Component (HOC), you could do something like this:
class Parent extends React.Component {
logWord = (word) => {
console.log(word);
}
render () {
return <ChildComponent handleLogging={ this.logWord } />
}
}
Then, in the ChildComponent, you simply access the method from props. For instance:
class ChildComponent extends React.Component {
render () {
return (
<div onClick={ this.props.handleLog.bind(null, 'Logged!') }>Click me to log a word!</div>
}
}
}
So, in your example, if you wanted a method that existed on the parent that updated a visibility attribute on your state, you could write:
class Parent extends React.Component {
constructor () {
this.state = {
visible: false
}
}
setVisible = (bool) => {
this.setState({ visible: bool });
}
render () {
return <ChildComponent updateVisible={ this.setVisible } visible={ this.state.visible } />;
}
}
ChildComponent:
class ChildComponent extends React.Component {
render () {
return (
<div>
<div onClick={ this.props.updateVisible.bind(null, true) }>Set me to visible!</div>
<div onClick={ this.props.updateVisible.bind(null, false) }>Set me to invisible!</div>
{ this.props.visible && <div>I'm visible right now!</div> }
</div>
}
}
}

Resources