ReactJS Why can't I modify children passed into a component - reactjs

I figured I could do this, but I am getting this error:
TypeError: child.constructor.ConvenienceConstructor is not a function
I have a component in a page, ala:
// this content is in an html page. My component reads in this child, but I can't seem to modify any part of it.. Just diplay it.
<MyComponent prop1="somevalue">
<div className="myclass1"> some child content that is dynamic </div>
</MyComponent>
Now, in my component since that inner child(ren) is dynamic, I need to change that class depending on some condition. But I can't. I get that error I noted above.
I tried this:
var childContent = React.Children.map(this.props.children,
function(child) {
return React.cloneWithProps(child,
{ className: 'myNEWClass' } );
});
I tried cloneElement too, that didn't work either.
Doesn't work. I tried accessing the child directly, ala:
child._store.props.className // but can't seem to change it, seems immutable.
So, how can I change that class up?
thanks,

Props are supposed to be immutable, so instead of passing className as a prop, you make the parent pass in a prop named defaultClass. In your map method, you can add an extra prop, say, overrideClass. Finally, in the render() method of the actual child component, you need some logic to set the className to either overrideClass, or defaultClass. In this way, you don't have to mutate props.

Related

React Context always returns EMPTY

I have a Search parent component and a SideBar child component, I am trying to get context in SideBar, but everytime it returns empty.
I followed the tutorial exactly like: https://itnext.io/manage-react-state-without-redux-a1d03403d360
but it never worked, anyone know what I did wrong?
Here is the codesandbox link to the project: https://codesandbox.io/s/vigilant-elion-3li7v
I wrote that article.
To solve your specific problem:
When using the HOC withStore you're injecting the prop store into the wrapped component: <WrappedComponent store={context}.
The value of the prop store is an object that contains 3 functions: get, set, and remove.
So, instead of printing it, you should use it. For example this.props.store.get("currentAlbums") or this.props.store.set("currentAlbums", [album1, album2]).
This example is forked by your code: https://codesandbox.io/s/nameless-wood-ycps6
However
Don't rewrite the article code, but use the library: https://www.npmjs.com/package/#spyna/react-store which is already packed, tested, and has more features.
An event better solution is to use this library: https://www.npmjs.com/package/react-context-hook. That is the new version of the one in that article.
This is an example of a sidebar that updates another component content: https://codesandbox.io/s/react-context-hook-sidebar-xxwkm
Be careful when using react context API
Using the React Context API to manage the global state of an application has some performance issues, because each time the context changes, every child component is updated.
So, I don't recommend using it for large projects.
The library https://www.npmjs.com/package/#spyna/react-store has this issue.
The library https://www.npmjs.com/package/react-context-hook does not.
You pass the store as a prop, so to access it, you need this.props.store in your SideBar.
Not this.state.store
Create a wrapping App component around Search and Sidebar:
const App = props => (
<div>
<Search />
<SideBar />
</div>
);
export default createStore(App);
Now you can manipulate state with set and get that you have available in child components Search and Sidebar.
In Search component you can have something like:
componentDidMount() {
this.props.store.set("showModal", this.state.showModal);
}
also wrapped with withStore(Search) ofc.
and in SideBar you can now call:
render() {
return (
<div>
{"Sidebar: this.state.store: ---> " +
JSON.stringify(this.props.store.get("showModal"))}
}
</div>
);
}
and you will get the output.

trying to call function in child component fails

I have two React components, Parent and Child, each is separate module in its own file. I'm using Redux, so both are "export default compose"...
In the Parent's constructor:
this.myChild = React.createRef();
In the Parent's render:
<Child ref={this.myChild} />
Child has method defined:
getAlert() {
//do something
}
I'm trying to call in one of Parent's method:
this.myChild.current.getAlert();
But I get:
this.myChild.current.getAlert() is not a function.
I verified that this.myChild.current is not null.
What am I missing?
Refs are used to access the DOM, not the React component (which is a JS class). As per the official docs on refs:
In the typical React dataflow, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props.
Avoid using refs for anything that can be done declaratively. For example, instead of exposing open() and close() methods on a Dialog component, pass an isOpen prop to it.

Although React doesn't allow objects as children, my code clearly says otherwise

So I came across this bizarre behavior — when I try to setState using objects, it only fails in SOME cases.
For example this works,
getUserClaimAmount().then(
userClaimAmount => {
this.setState({ userClaimAmount: userClaimAmount.toString()})
}
);
But the following does not. It will throw an error saying that React children are not allowed to be objects.
getUserClaimAmount().then(
userClaimAmount => {
this.setState({ userClaimAmount: userClaimAmount})
}
);
However, the following works for some reason. "bettingPoolTotal" is the same type as "userClaimAmount" above.
getBettingPoolTotal().then(
bettingPoolTotal => {
this.setState({ total: bettingPoolTotal });
}
);
Below is a screenshot of what the state looks like. It's clear that there's obviously React children that are indeed objects.
Example of React state
You've mixed up the children property and the state of the component.
children property is populated by React when you create the component. Considering the following JSX:
<Parent>
<Child1 />
text here
<Child2 />
</Parent>
The children property of Parent will be an array with three entries: the element created from Child1, string "text here" and the element created from Child2. If you try to pass the plain JavaScript object into the final markup (not into the React component, since it can use it as it want without error, but into native HTML tag), it won't work:
<div>
{{key: value}}
</div>
That's exactly the error you're getting. It seems that there is some element which has this.state.userClaimAmount passed as children entity, and so errors when it gets a plain object instead of string or JSX.
As for the state - it's entirely possible to have plain objects inside it; however, this should be used very cautiously. Consider the following case inside some component which has an obj field in its state:
const obj = this.state.obj;
obj.key = 'value';
this.setState({obj: obj});
The last setState here surprisingly become a no-op, since the state is already changed by this moment - through the reference copied to obj, - and then React, knowing that this is a no-op, doesn't trigger rendering, leaving component the same as before.

passing data from child to parent in react and undefind is not a function

I need to pass an array from child component to my parent component .
What i did in parent component is :
handlerfordata=(data)=>{
console.log('Inside handlerfordata data is');
console.log(data);
}
Inide return in render .Note Child is name of my child component
return(
<View>
<Child handlerfordata={this.handlerfordata()}/>
</View>
);
Now inside my child component i have done something like this
handleSave = () => {
//finalvalue is an array that is computed and i can see it in my console and handlesave is triggeed at onclick in child component inside return
console.log('finalValue is ',finalValue);
this.props.handlerfordata(finalValue);
}
Another thing is that child component gets rendered on the screen but i just want to access data from child component and not rendering it .
Pass the reference for handlerfordata and not this.handlerfordata().
It shuld be
<Child handlerfordata={this.handlerfordata}/>
^^^^^^^^^^^^^^^^^^^^^^
By adding this code
<Child handlerfordata={this.handlerfordata()}/>
You are not passing the reference, rather you are calling this function.
Change it to
<Child handlerfordata={this.handlerfordata}/>
which will just pass a reference.
Then you can call that from child component using props.
You have to bind your handler :
<Child handlerfordata={this.handlerfordata.bind(this)} />
Inorder to call the method you need to pass the reference in the child element as
<Child handlerfordata={this.handlerfordata}/>
You cannot access the data from child without rendering the child component.I prefer you to use redux so that all the states are there in a single store.
ReactJS is known for one way data flow(Top down) meaning whatever data that is flowing or passing, should be in one direction, from parent to child.
In the case where you need to pass data the other way round, perhaps try to apply redux state management instead.
In the code that you are trying as stated, it's only passing a method down from parent to child.

Children props are not visible in parent component

In child component, I set the props as following:
function mapStateToProps(state) {
return {
user : state.App.get('user'),
foo: 'ok'
}
}
But when I read this.props.children in render method of parent component, foo is not there. Anyone knows why?
I realized that I can't see the child state from a parent in my project. Am I missing something?
I'm also using Redux in this app. Whats wrong? What's the proper way of doing something like this.props.children.foo in parent Component?
You shouldn't be referencing this.props.children.foo to get foo. Once you've connected your component to mapStateToProps, you should be able to reference it just from this.props.foo
this.props.children will retrieve all the elements enclosed within an opening and closing tag of React component.
There is a CodePen example on the React documentation page that illustrates this:
http://codepen.io/gaearon/pen/ozqNOV?editors=0010
function WelcomeDialog() {
return (
<FancyBorder color="blue">
/*everything between these two blocks*/
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
/*is what is sent to FancyBorder as this.props.children*/
</FancyBorder>
);
}
Source: https://facebook.github.io/react/docs/composition-vs-inheritance.html

Resources