I am having a Parent Component and a child component
export default class CityPart extends Component {
constructor(props)
{
super(props);
this.state ={
citylist: citylist
selectedflag:1
}
}
Clickme(idd){
this.setstate({selectedflag:idd})
}
render() {
return (
<div className="CityPartMain">
{this.state.citylist.map((item)=>{
return (
<EachCity name ={item.name} key={item.id}
id={item.id}
selected={this.state.selected}
Clickme ={this.Clickme}
/>
)
})}
</div>
);
}
}
export default class EachCity extends Component {
render() {
const {name,id,selected,Clickme} = this.props;
return (
<button
onClick={this.Clickme(id)}
className={selected===parseInt(id,10)?"selectedcity": "EachCityMain"}>
<p>{name}</p>
</button>
);
}
}
whenever i click on the button i want that id should come to my parent component and it should get updated in the selectedflag of the parent state.
Thanks for help in advance.
You have made two mistakes.
First one is in your parent - this is how you should implement method Clickme:
Clickme = (id) => {
this.setState({selectedflag:idd})
}
In your implementation this means object, which is calling method (child), so this.setState() will work for child.
When you use lambda expression - it will work for parent.
Second mistake is how are you calling Clickme in your child component.
You should make it like:
<button
onClick={() => Clickme(id)}
className={selected === parseInt(id,10) ? "selectedcity" : "EachCityMain"}
>
<p>{name}</p>
</button>
If you are calling function without parameters, you can just pass function to onClick. In your case you have to create anonymous function to call it with parameter. Additionaly this is unnecessary.
Your Clickme callback is getting called right away (remember, function() is called right then) and you are just storing the result of that call in the onClick handler. You're also using this. Try instead setting it as a callback using an anonymous arrow function.
export default class EachCity extends Component {
render() {
const { name, id, selected, Clickme} = this.props;
return (
<button
onClick={() => Clickme(id)}
className={selected===parseInt(id,10) ? "selectedcity" : "EachCityMain"}
>
<p>{name}</p>
</button>
);
}
}
If this is unclear to you and how and why it works, I can add a codesandbox example with more detail.
Related
So right now, in my App file I have this:
{items.map(el => (
<Item
prop1={foo}
prop2={bar}
el={baz}
/>
))}
And in the <Item> component, I have this:
<span className={finishedClass ? "finishedItem" : ""}>
{props.el}
</span>
where finishedClass is a state variable.
So my question is, how can I check if finishedClass is true for every single <Item> component that gets generated as a result of the items.map?
So, you basically want to know if all the finishedClass state values in all the Item components are true. This can be simplified in the sense that if any of the Item components have finishedClass as false, you will perform a certain action.
So, what you can do is, pass a function as a prop to the Item component as follows:
{items.map(el => (
<Item
prop1={foo}
prop2={bar}
el={baz}
setFinishedClassToFalse={()=>{/*your statements*/}}
/>
))}
This function setFinishedClassToFalse will be called by the Item component if and only if its state value finishedClass is false. Obviously, there's a little more implementation to this than what I have described. But this should give you a start.
Parent component can communication with child component with parent props that have function in it. You can see code below onFinished property in Parent component has handleFinished() function value in it. That fucntion will be a bridge to help Child component to communicate with Parent component. On the Child component you must run onFinished props to triggering handleFinished function on Parent comoponent. In code below the trigger for props.onFinished is when <span> clicked by user.
import React from "react";
import ReactDOM from "react-dom";
import { Grid } from "react-flexbox-grid";
class App extends React.Component {
constructor(props) {
super(props);
this.state = { data: "test" };
}
render() {
const items = ["red", "green", "blue"];
const handleFinished = (e, index) => {
this.setState({ data: e });
console.log(this.state);
};
return (
<Grid>
{items.map((el, index) => (
<Child
prop1={"test"}
prop2={"test1"}
el={el}
onFinished={(e) => handleFinished(e, index)}
/>
))}
<div>{this.state.data.toString()}</div>
</Grid>
);
}
}
const Child = (props) => {
// example for your finishedClass value state
const finishedClass = true;
return (
<span
onClick={() => props.onFinished(finishedClass)}
className={finishedClass ? "finishedItem" : ""}
>
{props.el}{" "}
</span>
);
};
ReactDOM.render(<App />, document.getElementById("container"));
As finishedClass is a state variable, if you just console.log(finishedClass) inside component it will just do the work
Im learning react and very new to this, I am tinkering with something to understand this more.
I would like to know if it is possible to console.log the state of the CHILD using a prop passed down by the parent.
Example :
Child component ( has its own state)
Parentcomponent ( has its own state)
Child Component
this.state={
animal:'Lion'
}
<button onClick{this.props.giveMeState}>
And that, I would want to console the state ( animal:Lion)
Parent Component
this.state={
name: 'John'
}
giveMeState(){ ? what can go here, or is it not that simple ?
)
}
Codepen of example
Parent component cannot query the state of the child component. At least, that's not the intended design of React.
What I think you're asking is how to coordinate the state of child with parent, and you're on the right track to use a prop to pass the state from child to parent.
Perhaps a complete example that does what you want would look like this:
class Parent extends React.Component {
state = { name: "John" }
handleChildAnimal = animal =>
this.setState({ animal });
handleClick = e =>
console.log(`Child animal: ${this.state.animal}`);
render() {
return (
<div>
<Child onAnimal={this.handleChildAnimal} />
<button onClick={this.handleClick}>Tell me Animal state</button>
</div>
);
}
}
class Child extends React.Component {
state = { animal: "Lion" }
handleClick = e => {
console.log(`Animal: ${this.state.animal}`);
this.props.onAnimal(this.state.animal);
}
render() {
return (
<button onClick={this.handleClick}>{this.state.animal}</button>
);
}
}
Demo on CodePen.io
if you want to pass the state value of the child to the parent,
you can do it like this,
In the child component add another function getState and call the reference function giveMeState through this function
...
constructor(props) {
super(props)
this.state={ animal:'Lion' }
this.getState = this.getState.bind(this)
}
getState(){
this.props.giveMeState(this.state)
}
....
<button onClick={this.getState}>
....
and also redefine the parent function so that it takes a parameter
and the console.log that parameter
Not sure if this is a good pattern though
Here is another answer just for giving another example.
It does not fulfill your question and as told fulfilling your question would not be the best approach. Maybe you should try to think differently while working React and states.
App
class App extends React.Component {
state = {
input: "initial input state",
childState: "right now I don't know child state",
};
handleInputChange = e => this.setState({ input: e.target.value });
handleChildState = ( childState ) => this.setState( { childState } )
render() {
return (
<div style={styles}>
<h4>This is parent component.</h4>
<p>Input state is: {this.state.input} </p>
<p>Child state is: {this.state.childState}</p>
<hr />
<Input
onInputChange={this.handleInputChange}
getState={this.handleChildState}
/>
</div>
);
}
}
Child component as Input
class Input extends React.Component {
state = {
myState: "some state"
};
handleSendState = () => this.props.getState(this.state.myState);
handleState = e => this.setState({ myState: e.target.value });
render() {
return (
<div>
<h4>This is Child coponent</h4>
<button onClick={this.handleSendState}>
Click me to get child state
</button>
<p>This is my state: {this.state.myState}</p>
<p>Write something to change child's state.</p>
<input type="text" onChange={this.handleState} />
<p>
Write something to change parent's input state
</p>
<input type="text" onChange={this.props.onInputChange} />
</div>
);
}
}
I have some text. When you click on that element a modal pops up that lets you edit that text. The easiest way to make this work is to call setState on the child to initialise the text.
The other way, although more awkward, is to create an initial text property and make the child set it's text based on this.
Is there anything wrong with directly calling setState on the child or should I use the second method?
Although it is recommended to keep the data of your react application "up" in the react dom (see more here https://reactjs.org/docs/lifting-state-up.html), I don't see anything wrong with the first aproach you mentioned.
If you have to store data that is very specific of a child I don't see anything wrong in keep that information in the child's state.
It seems that your modal doesn't need to have its own state, in which case you should use a stateless React component.
This is one way of passing the data around your app in the React way.
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
initialText: "hello",
}
this.saveChildState = this.saveChildState.bind(this);
}
saveChildState(input) {
console.log(input);
// handle the input returned from child
}
render() {
return (
<div>
<ChildComponent
initialText={this.state.initialText}
save={this.saveChildState}
/>
</div>
);
}
}
function ChildComponent(props) {
return (
<div>
<input id="textInput" type="text" defaultValue={props.initialText}>
</input>
<button onClick={() => props.save(document.getElementById('textInput').value)}>
Save
</button>
</div>
)
}
Maybe I am misinterpreting your question, but I think it would make the most sense to keep the modal text always ready in your state. When you decide to show your modal, the text can just be passed into the modal.
class Test extends Component {
constructor() {
this.state = {
modalText: 'default text',
showModal: false
}
}
//Include some method to change the modal text
showModal() {
this.setState({showModal: true})
}
render(
return (
<div>
<button onClick={() => this.showModal()}>
Show Modal
</button>
{ this.state.showModal ? <Modal text={this.state.modalText}/> : null }
</div>
)
)
}
In the main component's render method, I have this line,
<BettingChips onClick={(betAmount) => this.handleClick(betAmount)} />
Which corresponds to this function,
handleClick(betAmount){
alert(betAmount);
}
However under the child component, I can't seem to pass arguments to the handleClick function,
class BettingChips extends Component{
render(){
return(
<div>
<button onClick={this.props.onClick} value={1} >1</button>
// ... etc
</div>
)
};
I can write this.props.onClick... But I can't write this.props.onClick(1) so that it passes in the integer value of 1 to the parent component. How do I work around that? Thanks.
It's quite simple. Just change
<button onClick={this.props.onClick} value={1} >1</button>
to
<button onClick={() => this.props.onClick(1)} value={1} >1</button>
Cheers!
Try to do this without using arrow function definition inside props (bad for child components performance, as will always be a new function reference more info here)
Parent class does not need the arrow function defined when passing onClick to BettingChips, we can do this at the class level instead, using arrow function to lexically bind this...
class SomeParentComponent extends Component {
handleClick = (betAmount) => {
alert(betAmount)
}
render() {
return <BettingChips onClick={this.handleClick} />
}
}
In BettingChips use event to extract the value from the target of the event (the button that was clicked), so you don't need to use arrow function with amount as parameter
class BettingChips extends Component {
onClick = (e) => {
this.props.onClick(e.target.value)
}
render() {
return(
<div>
<button onClick={this.onClick} value={1}>1</button>
// ... etc
</div>
)
}
}
This must work for you:
class BettingChips extends Component{
render(){
return(
<div>
<button onClick={() => this.props.onClick(1)} value={1} >1</button>
// ... etc
</div>
)
};
One way could be to create a new function in your child component and call your parent function from props there. This is useful if you need to perform some more complicated logic when the button is clicked. Here is a code example:
class BettingChips extends Component{
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
// do something else or prepare parameters for parent's `onClick`
this.props.onClick(1);
}
render(){
return(
<div>
<button onClick={this.onClick} value={1}>1</button>
</div>
);
};
I'm sure this is something trivial but I can't seem to figure out how to access the value of my button when the user clicks the button. When the page loads my list of buttons renders correctly with the unique values. When I click one of the buttons the function fires, however, the value returns undefined. Can someone show me what I'm doing wrong here?
Path: TestPage.jsx
import MyList from '../../components/MyList';
export default class TestPage extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
handleButtonClick(event) {
event.preventDefault();
console.log("button click", event.target.value);
}
render() {
return (
<div>
{this.props.lists.map((list) => (
<div key={list._id}>
<MyList
listCollection={list}
handleButtonClick={this.handleButtonClick}
/>
</div>
))}
</div>
);
}
}
Path: MyListComponent
const MyList = (props) => (
<div>
<Button onClick={props.handleButtonClick} value={props.listCollection._id}>{props.listCollection.title}</Button>
</div>
);
event.target.value is for getting values of HTML elements (like the content of an input box), not getting a React component's props. If would be easier if you just passed that value straight in:
handleButtonClick(value) {
console.log(value);
}
<Button onClick={() => props.handleButtonClick(props.listCollection._id)}>
{props.listCollection.title}
</Button>
It seems that you are not using the default button but instead some sort of customized component from another libray named Button.. if its a customezied component it wont work the same as the internatls might contain a button to render but when you are referencing the event you are doing it throug the Button component