how to attach ref to compose component - javascript

I am currently trying to get the child component functions using the ref in the following way but it doesn't show any of the details.
class ChildCompent extends React.Component {
constructor(props){
super(props);
}
_function1 =()=>{
/* ...... */
}
_function1 =()=>{
/* ...... */
}
render (){
return (
<div>
ChildComponent
</div>
)
}
}
let ComposedChild = compose(
/* --- graphql query */
)(ChildComponent);
class ParentComponent extends React.Component {
constructor(props){
super(props);
}
_onClick = ()=>{
console.log(this.refs.childComponent)
// doesn't show the _function1 and _function2
}
render (){
return (
<div onClick={this._onClick}>
<div>Testing</div>
<ChildComponent ref="childComponent"/>
</div>
)
}
}

You should make use of ref callback to set ref on a component
See this answer:
How to access a DOM element in React? What is the equilvalent of document.getElementById() in React
After that to access another component's function you can do that like this.childComponent._function1()
Also you need to make use of the component returned after wrapping it with the compose function in the ParentComponent.
class ChildComponent extends React.Component {
constructor(props){
super(props);
}
_function1 =()=>{
/* ...... */
console.log('hello');
}
render (){
return (
<div>
ChildComponent
</div>
)
}
}
let ComposedChild = compose(
/* --- graphql query */
)(ChildComponent);
class ParentComponent extends React.Component {
constructor(props){
super(props);
}
_onClick = ()=>{
this.childComponent._function1()
// doesn't show the _function1 and _function2
}
render (){
return (
<div onClick={this._onClick}>
<div>Testing</div>
<ComposedChild ref={(ref) => this.childComponent = ref}/>
</div>
)
}
}

Related

how to pass state from child component to parent component in reacts

I have a parent component
class ParentComponent extends React.PureComponent {
render(){
return(
//IN HERE I'm calling child parent
<ChildComponent/>
)
}
}
class ChildComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
sample: '',
};
}
how can I get the sample state to the parent component?
So at the Parent Component make a method which receives value in return.
StateValue = (value) =>{
console.log(value);
}
Pass this method as props to the child component.
<ChildComponent method={this.StateValue}/>
At the child component Pass the state value to the method props received in step 2.
constructor(props) {
super(props);
this.state = {
sample: 'hi',
};
}
render(){
this.props.method(this.state.sample)
return(
<></>
)
You will get your state value in StateValue Method from the props in your parent component.
Try this:
class ParentComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
sample: '',
};
}
render(){
return(
<ChildComponent sample={this.state.sample} setState={(sample) => this.setState({ sample })} />
)
}
}
class ChildComponent extends React.PureComponent {
// you can now call this.props.setState(value); to set parent component state.
// and access the sample state: this.props.sample;
}
One option is to specify a callback as a prop. Like this:
class ParentComponent extends React.PureComponent {
onSample = (sample) => {
// handle sample
}
render(){
return(
//IN HERE I'm calling child parent
<ChildComponent
callback={this.onSample}
/>
)
}
}
class ChildComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
sample: '',
};
this.onSample = props.callback
// call later on via this.onSample(<sample>);
}

React parent-child communication: TypeError: _this.state.myFunction is not a function

I'm new to the world of React and I'm trying to build a parent component with a function that should be invoked from a child component. However, when I call the function, I get the error message in the title. I have something similar:
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.myFunction = this.myFunction.bind(this);
}
myFunction(param) {
//do something
}
render(){
return(
<ChildComponent event={this.myFunction} />
);
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
inheritedFunction: this.props.event
};
}
childFunction(param) {
//do a few things first
this.state.inheritedFunction(param);
}
render(){
return(
<input type="checkbox" onChange={this.childFunction.bind(this)></input>
);
}
}
My code compiles and runs, and then when it gets to execute the childFunction( ) upon selecting the checkbox, this.state.inheritedFunction(param) says that it is not a function and the application collapses. I suspect that it has to do something with binding, but I'm really not sure and stuck with this problem.
I'm new to React, so please be nice. :-) Anyone knows what I messed up?
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.myFunction = this.myFunction.bind(this);
}
myFunction = (param) => {
//do something
alert(param);
}
render(){
return(
<ChildComponent event={this.myFunction} />
);
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
inheritedFunction: this.props.event
};
}
childFunction(param) {
//do a few things first
this.props.event(param);
}
render(){
return(
<input type="checkbox" onChange={this.childFunction.bind(this)></input>
);
}
}
I think your problem is trying to save a reference inside the state and then on the onchange callback you are binding again the function.
remove the state on the constructor and just call it directly from props
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.myFunction = this.myFunction.bind(this);
}
myFunction(param) {
//do something
}
render(){
return(
<ChildComponent event={this.myFunction} />
);
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.childFunction = this.childFunction.bind(this); // bind on the constructor.
}
childFunction() {
//do a few things first
this.props.event(this) //call the prop directly here.
}
render(){
return(
<input type="checkbox" onChange={this.childFunction></input> // no more binding here
);
}
}
class ParentComponent extends React.Component {
constructor(props) {
super(props);
}
myFunction = param => {
//do something
};
render() {
return <ChildComponent event={this.myFunction} />;
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
}
childFunction = (param) => {
//do a few things first
this.props.event(param);
}
render() {
return <input type="checkbox" onChange={this.childFunction} />
}
}

Running method of component child from this.props.children array

import React from "react";
import ReactDOM from "react-dom";
class NestedComponent extends React.Component {
constructor(props) {
super(props);
this.childMethod = this.childMethod.bind(this);
}
childMethod() {
alert("Child method one ran");
}
render() {
return <div>NestedComponent</div>;
}
}
class NestedComponentTwo extends React.Component {
constructor(props) {
super(props);
this.childMethod = this.childMethod.bind(this);
}
childMethod() {
alert("Child method two ran");
}
render() {
return <div>NestedComponentTwo</div>;
}
}
class WrappingComponent extends React.Component {
constructor(props) {
super(props);
this.runMethod = this.runMethod.bind(this);
}
runMethod() {
let child = this.props.children[0];
/** Always returns as undefined */
//if (typeof child.childMethod == "function") {
// child.childMethod();
//}
/**
* EDIT: Close, however the this binding seems to not be working. I can however provide the childs props to the childMethod and work with that.
*/
if(typeof child.type.prototype.childMethod == "funciton"){
child.type.prototype.childMethod();
}
}
render() {
return (
<div>
{this.props.children}
<button onClick={this.runMethod}>run</button>
</div>
);
}
}
const App = ({}) => {
return (
<div>
<WrappingComponent>
<NestedComponent />
<NestedComponentTwo />
</WrappingComponent>
</div>
);
};
if (document.getElementById("example")) {
ReactDOM.render(<App />, document.getElementById("example"));
}
So the goal is to have optional methods attached to a nested component that can execute from the wrapping component, almost like an event emmiter. For some reason though, the method that exists on the child component claims not to exist. However whenever I log the child component pulled from the array of the this.props.children the prototype has the method listed.
Am I missing a special way to access methods of children components through a methods variable perhaps?
Found the variable I can use to access it. If anyone has any more insight into this, or reasons why what I am doing is poor practice please let me know.
Editing the question where this is needed, but the item below is accessing the function of the child:
child.type.prototype.childMethod
Does not appear to maintain the this binding. Passing props down does work however.
You should manage all of this logic in the top level component (the App component)
class NestedComponent extends React.Component {
constructor(props) {
super(props);
this.childMethod = this.childMethod.bind(this);
}
childMethod() {
alert("Child method one ran");
}
render() {
return <div>NestedComponent</div>;
}
}
class NestedComponentTwo extends React.Component {
constructor(props) {
super(props);
this.childMethod = this.childMethod.bind(this);
}
childMethod() {
alert("Child method two ran");
}
render() {
return <div>NestedComponentTwo</div>;
}
}
class WrappingComponent extends React.Component {
render() {
return (
<div>
{this.props.children}
<button onClick={this.props.onClick}>run</button>
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.runMethod = this.runMethod.bind(this);
}
runMethod() {
if (this.nestedComponent) {
this.nestedComponent.childMethod();
}
}
render() {
return (
<div>
<WrappingComponent onClick={this.runMethod}>
<NestedComponent ref={el => this.nestedComponent = el} />
<NestedComponentTwo />
</WrappingComponent>
</div>
);
}
};
if (document.getElementById("example")) {
ReactDOM.render(<App />, document.getElementById("example"));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="example"></div>
Moreover ref with string attribute is deprecated https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs

Show sibling components reactJs

I'm new on react world, I would show components from sibling components.
I have parent component:
import Toast from './components/Toast/Toast'
class App extends Component {
constructor(){
super();
this.state = {
showToast:false
};
}
render() {
return (
<div id="cont">
<Toast showToast={this.state.showToast}/>
<Header />
</div>
);
}
}
In my Toast component:
class Toast extends Component {
constructor(props) {
super(props);
}
render() {
const showToast = this.props.showToast;
let toast = null;
if (showToast) {
toast = <div className="visible">Toast Ok</div>;
}else{
toast = null;
}
return (
<div>
{toast}
</div>
);
}
}
export default Toast;
And in my Header component I have:
class Header extends Component {
render() {
return (
<button> // With click, show toastComponents so setState parent </button>
)
}
So if I click on button I would set state key showToast for show my components.
You can pass a function down to your <Header> component, then call it when the button is clicked.
let showToast = () => this.setState({ showToast: true });
// ...
<Toast showToast={this.state.showToast}/>
<Header onClick={showToast}>
Then all you need to do is pass this prop through to the click handler inside <Header>.
<button onClick={this.props.onClick}>

What does "Warning: setState(...): Can only update a mounted or mounting component" mean?

So I have one root component and two child components. I have trying to get one child to call a method that is up in in the root component and update the state up in the root component, and pass the updated down to the other component, but I am getting the following error.
What could be the issue?
warning.js?8a56:36 Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the firstChild component.
Here is the code:
firstChild.js
export default class firstChild extends React.Component {
constructor(props) {
super(props);
this.state = {
nameText: '',
}
}
nameChange(event) {
this.setState({
nameText: event.target.value,
})
}
submitClick() {
var nameText = this.state.nameText;
this.props.saveName(nameText)
this.setState({nameText: ''});
}
render() {
var st = this.state;
var pr = this.props;
return (
<input
placeholder='Enter Name'
onChange={this.nameChange.bind(this)}
value={this.state.nameText}
/>
<button
onClick={this.submitClick.bind(this)}
/>
And in root component, App.js:
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
submitSuccess: false
}
}
saveName(nameText) {
this.setState({submitSuccess: true});
}
render() {
var props = {};
props.submitSuccess = this.state.submitSuccess;
return (
<div>
<firstChild
saveName={this.saveName.bind(this)}
/>
{React.Children.map(this.props.children, function(child) {
return React.cloneElement(child, props);
})}
</div>
)
}
}
And my secondChild.js:
export default class secondChild extends React.Component {
static propTypes = {
submitSuccess: React.PropTypes.bool.isRequired,
}
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<div>
{this.props.submitSuccess}
</div>
)
}
}
Fisrt, rename all your React components as Camel Case like this.
class firstChild ... --> class FristChild
<fristChild> --> <FristChild>
Second, in your FirstChild render method, you should wrap your elements into an enclosing tag like this:
class FirstChild extends Component {
render(){
return (
<div>
<input ... />
<button ... />
</div>
)
}
}
Third, when you use cloneElement upon this.props.children, you should use Proptypes.<type> in your secondChildren instead of Propstypes.<type>.isRequired. Check it here to see why.
class SecondChild extends Component {
static propTypes = {
submitSuccess: React.PropTypes.bool, // remove isRequired
}
}
Regardless all above, I have tested your code and it works fine.
You can try and use componentWillUnmount lifecycle function in order to check when the component is unmounted.
You can also use a flag to signal that the component is unmounted before setting the state:
saveName(nameText) {
if (!this.isUnmounted){
this.setState({submitSuccess: true});
}
}
componentWillUnmount() {
this.isUnmounted = true;
}

Categories