if I have a class
class Role extends Component {
constructor(props) {
super(props);
this.state = {
role: 'something',
value: 1
}
}
render() {
let roleStatus = [];
for (let key in this.state) {
roleStatus.push(<p key={key}>{key}: {this.state[key]}</p>)
}
return (
<div>
<div>
{roleStatus}
</div>
</div>
);
}
and then another class that uses composition (asrecommended by React doc)
class specialRole extends Component {
constructor(props) {
super(props);
// I want to add some other attributes to this.state
}
render() {
return <role />
}
}
}
I want to be able to add another attribute, let's say name, to this.state, but when I use setState to add it, the render doesn't reflect to it. I'm wondering if it's because setState is not synchronized function. If that's the case, how should I achieve what I want to do?
What you'll want to do is think of it like a parent/child composition.
The parent has the logic and passes it to the child, which then displays it.
In your case, the parent should be Role, and the child component be something that renders Role's states, for example: RoleStatus. In addition, you can have another component called SpecialRoleStatus. Note the capitalized component names, component names should be capitalized.
The composition would look something like this:
class Role extends React.Component {
constructor(props) {
super(props)
//lots of state, including special ones
}
render() {
return(
<div>
<RoleStatus normalState={this.state.normalState} />
<SpecialRoleStatus specialState={this.state.specialState} />
</div>
)
}
}
Also, setState() won't behave like you want it to because it does not set the state of any other component other than its own component.
Related
I want to change some inner property of a prop. Props claim to be immutable, but when I change the value, the parent's state value is getting changed.I read that props are immutable. But changing the value is reflecting in parent.
class ParentComp extends React.Component {
constructor(props) {
super(props);
let property = {someProperty:'ABCD'};
this.state={
myState: property
}
}
render() {
return(
<div>
Parent:{JSON.stringify(this.state.myState)}
<ChildComp pState={this.state.myState} />
</div>
);
}
}
class ChildComp extends React.Component {
render() {
this.props.pState.someProperty = '1234';
return(
<div>
Child:{JSON.stringify(this.props.pState)}
</div>
);
}
}
At the end, I see both the values are changed to 1234. In online fiddles, it is working as expected(ie., parent value is not changed.). But in my project, the parent is being changed.
How do I achieve this usecase, wherein I want to change some properties in props, and not reflect in the parent's state?
I read that props are immutable
That's not true - you only should treat them as they were immutable. In other words, they are just regular javascript Objects and you should not mutate them.
If you want to change the value of the props, you should dump the props in the state first then do the mutation on that state.
Mutating props is not best practice. So your ChildComp should be like:
class ChildComp extends React.Component {
constructor(props) {
super(props);
this.state = {
pState: props.pState,
}
}
componentDidMount() {
const { pState } = this.state.
pState.someProperty = '1234';
this.setState({
pState,
});
}
render() {
return(
<div>
Child:{JSON.stringify(this.state.pState)}
</div>
);
}
}
I have 3 components, that is 2 child components and one parent component.
I wanted to pass the child component value to parent (only the values not the components enitirely,it should not visible in parent) and this values from parent to another child component.
Any suggestions or logic of how to proceed on this, since I don't have any guidance as of right now I had to ask here. Is the above problem possible.
The code is very complex, so I have not put here.
Thank you
When you say values, do you mean state, props, user input, something else?
If you mean state or props: React has a 1-way data flow, so the easiest way to accomplish this is to actually store the data at a higher level. Either store the data used by the child in the parent and pass it down to the children for consumption, or else use a store that both parent and children have access to. Either way, this will make it much easier for all components to access the data.
If you mean user input: one way you can accomplish this is to pass a callback from the parent component to the child as a prop, and then in the child call that callback when a user does something or changes some value. The callback function can make the data accessible to the parent on that user action, and then you can decide what to do with the data from there.
AksharaDL,
Child to Parent — Use a callback and states
Parent to Child — Use Prop
Also here is another article explaining it: https://medium.com/#ruthmpardee/passing-data-between-react-components-103ad82ebd17
here is the solution.
in parrent component you have a state. and have a setData method to update state. pass setData to ChildOne use props. and data to ChilTwo and use it
class StoreBanner extends React.Component {
constructor() {
this.state = {
data: 'whatever'
}
}
setData = (data) => {
this.setState({data})
}
render() {
return (
<div>
<ChildOne setData={this.setData}/>
<ChildTwo data={this.state.data}/>
</div>
)
}
}
and in ChildOne you can update the parrent state
class ChildOne extends React.Component {
setParentData = () => {
this.props.setData('another')
}
...
}
You can do it like this.
class ParentComp extends React.Component {
constructor() {
super();
this.state = {
theStateToPass: null
}
this.receiveDataFromChild = this.receiveDataFromChild.bind(this);
}
receiveDataFromChild(data) {
this.setState({
theStateToPass: data
})
}
render() {
return (
<div>
<FirstChild updateMe={this.receiveDataFromChild} />
<SecondChild stateFromFirstChild={this.state.theStateToPass} />
</div>
)
}
}
class FirstChild extends React.Component {
constructor(props) {
super(props);
this.callParentMethod = this.callParentMethod.bind(this);
}
callParentMethod(e) {
let someDataToSend = "ABC";
this.props.updateMe(someDataToSend)
}
render() {
return (
<div onClick={this.callParentMethod}>
</div>
)
}
}
class SecondChild extends React.Component {
render() {
return (
<div>
{this.props.stateFromFirstChild}
</div>
)
}
}
however it becomes complex and might lead to one's pulling their hair out. so i would suggest using redux , it keeps the flow simple , you have a reducer , actions and a container. everything goes with a flow and keeps it clean but it does comes with an extra overhead of more code as you will be creating container reducer and actions.
I want to build a select input component with React.
The select should be dumb component as it's only a UI Component,
but it also have it's own state (Whether to show the options list, or not)
How should I manage this state?
return (
const Select = (props) => {
<div>
<label>{placeholder}</label>
{/*some toggle state*/ && <div>props.children</div>}
</div>
}
)
thanks!
You should not get too confused by the fact that "it's only a UI component". Anything that has an internal state should be a class.
Your code, a dropdown, is my go-to example of when you should use internal state.
Manage your state with setState().
Now your component is stateless, but you need a stateful.
For example:
class Select extends React.Component {
constructor(props) {
super(props);
this.state = {value: '', toggle: false};
}
render() {
return (
<div>
<label>{placeholder}</label>
{this.state.toggle && <div>this.props.children</div>}
</div>
);
}
}
And you should change state with setState function.
For more information, check this article.
According to your code, what you are rendering is a stateless component, so it will not have any state.
What you can do is pass the state from the parent to this component like so:
constructor(props) {
this.state = { showDumbComponent:true }
}
render() {
<DumbComponent show={this.state.showDumbComponent} />
}
I have a component that receives images as props, performs some calculation on them, and as a result I need to update its class. But if I use setState after the calculation, I get the warning that I shouldn't update state yet... How should I restructure this?
class MyImageGallery extends React.Component {
//[Other React Code]
getImages() {
//Some calculation based on this.props.images, which is coming from the parent component
//NEED TO UPDATE STATE HERE?
}
//componentWillUpdate()? componentDidUpdate()? componentWillMount()? componentDidMount()? {
//I CAN ADD CLASS HERE USING REF, BUT THEN THE COMPONENT'S
// FIRST RENDERED WITHOUT THE CLASS AND IT'S ONLY ADDED LATER
}
render() {
return (
<div ref="galleryWrapper" className={GET FROM STATE????}
<ImageGallery
items={this.getImages()}
/>
</div>
);
} }
You should put your logic into componentWillReceiveProps (https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops) so as to do a prop transition before render occurs.
In the end what we did was run the logic in the constructor and then put the class into the initial state:
class MyImageGallery extends React.Component {
constructor(props) {
super(props);
this.getImages = this.getImages.bind(this);
this.images = this.getImages();
this.state = {smallImgsWidthClass: this.smallImgsWidthClass};
}
getImages() {
//Some calculation based on this.props.images, which is coming from the parent component
this.smallImgsWidthClass = '[calculation result]';
return this.props.images;
}
render() {
return (
<div className={this.state.smallImgsWidthClass }
<ImageGallery
items={this.images}
/>
</div>
);
}
}
I have a parent component with child elements. I tried to add a child element after the parent component mounted:
class Parent extends React.Component {
componentDidMount() {
this.props.children.push(<NewChildComponent/>)
}
render() {
return (
<div>
{this.props.children}
</div>
)
}
}
Can someone tell me
1. How to add a child element after a parent has mounted
2. Why the above did not work
It's not working because you are mutating the props array manually - React has no idea that it has changed. In general, you should never change props at all.
If you really want to do this, you can use setState within componentDidMount, and then render your child component through that:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
childComponent: null
}
}
componentDidMount() {
this.setState({ childComponent: <div>Hello</div> });
}
render() {
return (
<div>
{this.state.childComponent}
</div>
)
}
}
However, there might be a better solution to whatever you're trying to do. I can't imagine many situations in which you'd want to render stuff only after the parent has mounted.
Can you please try componentWillMount, I guess this will fix the problem