Functions passed to react component children don't receive function context - javascript

I am getting stuck while using react, wherein, I am passing a function from a parent component to multiple children components. That function calls other functions that also reside within the parent component.
The children components do successfully start the function, but unfortunately, the function fails because it seems to not have the same context from within the children's elements, eg. it begins calling the other functions stored within the parent element, and receives undefined. This is strange because the error is coming from the parent component file, not the child component file.
I was not sure whether to pass all the functions to the children elements, which feels rather bulky, and also feels like I would still be missing important function context.
I have tested running the same function on the parent component and it has no issues, almost like the function context from the parent component is not passed to the child component, only the function itself.
Is that correct?
Here is an example where the child component has a button to click that would run the function that was passed from the parent component and includes running other functions from within the parent component, updating state and making changes, etc.
Parent element:
class Content extends Component {
constructor(props) {
super(props);
this.state = {
name: "React",
toggle: true,
...
};
}
toggleComponent(name) {
this.toggling(name); // THIS IS WHERE THE ERROR OCCURS ON THE CHILD ELEMENT, undefined.
}
toggling(name) {
does some stuff...
}
render() {
return (
<Comp toggleComponent={this.toggleComponent}/>
)
}
Child element:
class Demo1 extends Component {
constructor(props) {
super(props);
this.state = {
name: "React"
};
}
render() {
return (
<div className="button" onClick={() => this.props.toggleComponent('theCompName')}>Continue</div>
)
Let me know what can be done to pass the additional context to the children components or if there is a better way to do this.
Thanks, you are all very smart.

In your constructor for your Content class, try binding your toggleComponent function to the class using .bind():
constructor(props) {
super(props);
this.state = {
name: "React",
toggle: true,
...
};
this.toggleComponent = this.toggleComponent.bind(this);
}
Class methods are not "bound" to the class by default. This means that your this keyword in toggleComponent does not refer to the Content class until you specify it using .bind().
Hope this helps!
More info can be found here: https://reactjs.org/docs/handling-events.html

Use arrow syntax in the parent component's functions. That will allow the functions in the parent component to execute in the parent component's context. Otherwise you'll have to do a bunch of binding(this) crap to make that work properly.

Related

Can you stop a nested child node from executing its constructor until a parent node has constructed?

Imagine a scenario where I have the following DOM tree
<body>
<parent-component>
<div>
<child-component></child-component>
</div>
</parent-component>
</body>
The child component has a seekParent function that fires off a CustomEvent that should be caught by the <parent-component>, which then uses a callback to tell the child this is the parent component node.
Consider when the child component is is defined via customElements.define() first. The child's constructor fires off the CustomEvent as soon as <child-component> is defined, since parent nodes do not need to be valid and at this stage be HTMLUnknownElement.
The event bubbles through the <parent-component> without being caught because that component has not yet called its constructor, to attach an event listener.
Is it at all possible to not parse child nodes within a DOM tree until a parent becomes defined / valid Element? Otherwise, is there any way around this issue besides using a setTimeout()?
Thanks
Perhaps you could make a component that delays the rendering until it's mounted:
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
mounted: false,
}
}
componentDidMount() {
this.setState({mounted: true});
}
render() {
if (!this.state.mounted) return null;
return this.props.children;
}
}

Javascript is it bad to replace a function with bound version of itself

I have a react component that has to pass a method to its children so that they can modify the state. So I created a function that allows to do that. I know I should bind the parent component to the this parameter of the function so that the children can successfully modify the state. The reason I want to do this is silly: I just don't know what to name the bound version ¯\_(ツ)_/¯. So what wanted to do is:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.modifyState = this.modifyState.bind(this);
}
modifyState() { /* blah blah*/ }
render() {
return(
<Child modifyState={this.modifyState} />
);
}
}
Now my question is:
Is there a reason why I really don't want to do this, can it cause any problems?
The reason I ask is, if there were no downsides, why not have this be the default behavior of it, in other languages this is always an instance of the class where the function (method) is defined. If you wanted the current behavior (this is the object who called the function from my understanding) just declare a global function.

Call class' function inside static array of class

I am trying to pass the onClickItem function down to the Card component as a prop, so that when it is clicked the state in the current component is updated.
class CurrentComponent extends Component {
...
constructor(props) {
super(props);
this.onClickItem = this.onClickItem.bind(this);
...
onClickItem() {
this.setState({something: true});
}
static cards = [
{ position: 8, element: <Card position={8} onItemClick={this.onClickitem}/> }
];
render() {
...
}
The this inside the static array is undefined. I was wondering how I can pass the function down. It is possible to move the array declaration inside the render, but I do not want it initialized every time the component renders. Any insight appreciated!
take the keyword "static" off the array declaration and it will work fine.
to understand the reason why it works without static and understand how static is treated in general you can look at this code -> transpiled on right
https://www.typescriptlang.org/play/#src=class%20context%20%7B%0D%0A%20%20%20%20somethingelse%20%3D%205%3B%0D%0A%20%20%20%20testing%20%3D%20%5B%0D%0A%20%20%20%20%20%20%20%20this.somethingelse%0D%0A%20%20%20%20%5D%0D%0A%7D%0D%0A%0D%0Aclass%20contex2t%20%7B%0D%0A%20%20%20%20somethingelse%20%3D%205%3B%0D%0A%20%20%20%20static%20testing%20%3D%20%5B%0D%0A%20%20%20%20%20%20%20%20this.somethingelse%0D%0A%20%20%20%20%5D%0D%0A%7D

How can a parent alter props for a child component in react?

I'm new to react, and am a little confused about something. I've read many articles online claiming that a component cannot alter its own props, but that a parent can alter the props of its children. However, I have seen nothing that actually shows how to do this.
I would like to be able to do this:
class Parent extends Component {
constructor(props) {
super(props);
this.childProps = {name:'name',age:12,type:'child'};
this.changeChild = this.changeChild.bind(this);
}
changeChildName(newName) {
//change prop 'name' of child here;
}
render() {
return (
<Child {...this.childProps} />
);
}
}
However, I can't figure out how to do this at all - despite almost all the material that I've read on React saying that a parent can change its child's props. What I can get to work properly is as follows:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {name:'name',age:12,type:'child'};
this.changeChild = this.changeChild.bind(this);
}
changeChildName(newName) {
this.setState({name: newName});
}
render() {
return (
<Child {...this.state} />
);
}
}
It seems a bit overkill to me that the Parent needs to re-render when the only thing that I want to re-render is the child view. How can I change the props of the <Child> component from the <Parent> component?
Secondary Questions
1) Is it possible to change the state of a component without having the component re-render?
2) Is there an onStateChange type event that we can tap into, or do we solely have componentWillReceiveProps?
1) Is it possible to change the state of a component without having the component re-render?
No, and it makes very little sense.
2) Is there an onStateChange type event that we can tap into, or do we solely have componentWillReceiveProps?
There is no, use componentWillReceiveProps.
It seems a bit overkill to me that the Parent needs to re-render when the only thing that I want to re-render is the child view.
Actually this is where you trick yourself: the parent IS changed, since what it returns is changed. The whole tree is being re-rendered from the root.
I think you misunderstand. It is very simple for a parent to change the child props... Just change the props that get rendered. Now, what if we want to do some changes in child without rerendering the parent. This is also pretty simple.
Attach a ref to your child and work with it. Now, the child cannot change its own props, so anything you mess with within the child will not be a prop. Props are passed down from the parent every time the parent rerenders.
So,
class Parent extends Component {
constructor(props) {
super(props);
this.childProps = {name:'name',age:12,type:'child'};
}
doSomethingOnChild() {
this.refs.child.callFunctionOfChildThatWillMessWithItself();
}
render() {
return (
<Child {...this.childProps} ref="child" />
);
}
}

React: pass ref through?

I'm trying to figure out how to get access to a "public" method on a React Component, that's been decorated with any number of higher-order components. Something like this:
class Toolbar extends React.Component {
openSubMenu(menuName) {
// whatever
}
render() {
// whatever
}
}
export default compose(
connect(mapStateToProps, mapDispatchToProps),
preload(), // custom higher order component which displays loading state
)(Toolbar);
If I now get a ref on the toolbar, the openSubmenu method isn't available, because it's hidden under (in this case 2) higher order components. Is there anyway to get to an arbitrary method on the underlying component?
Refs Aren't Passed Through
While the convention for higher-order components is to pass through all props to the wrapped component, it's not possible to pass through refs. That's because ref is not really a prop — like key, it's handled specially by React. If you add a ref to an element whose component is the result of an HOC, the ref refers to an instance of the outermost container component, not the wrapped component.
check https://facebook.github.io/react/docs/higher-order-components.html
Check the working demo: JSFiddle
Based on the one-way data flow nature of React, a component function is always triggered by some passed-in props value:
var Toolbar = React.createClass({
render: function() {
console.log(this.props);
return <div className={this.props.active ? "active" : ""}>Menu Item</div>;
}
});
var Parent = React.createClass({
open: function() {
this.setState({
subMenuActive: true
});
},
render: function() {
console.log(this.state);
var isActive = (this.state || {})['subMenuActive'];
return <div><Toolbar active={isActive}></Toolbar><button onClick={this.open}>Open sub menu</button></div>;
}
});
So the process should be reversed, which means: a component should be used by others, which will trigger different behaviours by specifying different props value.
If you want to trigger some specific function inside the component (instead of changing a className in the example), you need to write some code in some special functions like componentWillReceiveProps or componentDidMount. There functions will be called by React at some particular moment: https://facebook.github.io/react/docs/component-specs.html

Categories

Resources