Passing value from Parent to Child in Reactjs using props - javascript

I am trying to pass theExpert.email value to another child component whenever i click on send questions button.
This is the constructor of the Parent class
constructor() {
super();
this.state = {
textbox: '',
category: '',
exp: '',
hide: false
};
this.hideButton = this.hideButton.bind(this);
}
The follow function hides the button once it is clicked and saves the value of the theExpert.email in exp, (value is passed correctly since console.log prints it)
hideButton (value) {
this.setState({ hide: true });
this.setState({
exp: value
});
console.log(value)
}
And here is the button that once I click on it it passes the value to hideButton
<div>
{!this.state.hide ? (
<button onClick={() => this.hideButton(theExpert.email)}>Ask Me!</button>
) : null}
</div>
Now what i want to do is once i click on Send Questions button i get redirected to the child component Questions.js and pass the value of theExpert.email to that component
The button Send Questions:
<div>
<p>
{(this.state.hide) && (
<Link to="/questions">
<button
style={{ background: "green", color: "white" }}
>
Send Question
</button>
</Link>
)}
</p>
</div>
How can i retrieve value in the child class to create a post request using it

I think the issue us due to react being lazy. Basically you are just setting hide to true and re-rendering your component and all of its children but never setting exp the expected value.
So instead of
hideButton (value) {
this.setState({ hide: true });
this.setState({
exp: value
});
console.log(value)
}
try
hideButton (value) {
this.setState(prevState=>{
prevState= {
...prevState
hide: true ,
exp: value
}
return prevState
});
}

Related

React.js Getting State to Immediately Update

I'd like for my state to update changes to immediately be shown when state changes, but I can't seem to figure out why It isn't. Basically when a user clicks on a dropdown item from the menu, the items inner text ... that they clicked on should appear as an h1 on the screen, but instead it doesn't appear until the next click. How can I change this? Hopefully I made sense. Code can be found here.
Parent Component (APP):
class App extends React.Component {
state = {
loading: true,
bases: ['USD', 'EUR', 'AUD', 'CAD', 'JPY', 'NZD'],
selectedBase: null
};
// When Component Mounts Overlay goes for 3 Seconds
componentDidMount() {
setTimeout(() => this.setState({
loading: false,
}), 3000)
this.onBaseChange('USD');
}
// When User selects a new Base in Search Component, state is updated
onBaseChange = newBase => {
this.setState({ selectedBase: newBase });
}
// need to find out how to see state change immediatly after its updated!
// Rendered Content:
render(){
return (
<>
{this.state.loading === false ? (
<div className="App">
<div id="one">
<h1>{this.state.selectedBase}</h1>
<Search bases = {this.state.bases} selectedBase = {this.state.selectedBase} onBaseChange = {this.onBaseChange}/>
</div>
</div>
) : (
<Overlay />
)}
</>
);
}
}
export default App;
Child Component (Search):
class Search extends Component {
state = {
dropdownVisible: false,
term: '',
selectedBase: this.props.selectedBase
};
// when a base is clicked from dropdown, the selectedBase is updated, term is set back to empty, and dropdown back to non-visible.
// passing state of child up to parent through prop
// clearing input search on click
onBaseSelect = (event) => {
// when an base is clicked from dropdown, the selectedBase is updated, term is set back to empty, and dropdown back to nonvisible.
this.setState({
selectedBase: event.target.innerHTML,
term: '',
dropdownVisible: false
})
// passing state of child up to parent through prop
this.props.onBaseChange(this.state.selectedBase)
// clearing input search on click
document.getElementById("input_search").value = "";
}
render(){
return(
<div id="search">
<div id="dropdown" style={{display: this.state.dropdownVisible ? "block" : "none"}}>
<ul>
{/* filterng out base array based on users input */}
{this.props.bases.filter(base => base.includes(this.state.term.toUpperCase())).map((filteredBase, index) => (
<li onClick = {this.onBaseSelect} key={index}>{filteredBase}</li>
))}
</ul>
</div>
</div>
)
}
}
export default Search
this.setState is an asynchronous function, so when you do
// passing state of child up to parent through prop
this.props.onBaseChange(this.state.selectedBase)
// clearing input search on click
document.getElementById("input_search").value = "";
the state is not yet updated. So send that code as as a callback to this.setState like this,
onBaseSelect = (event) => {
// when an base is clicked from dropdown, the selectedBase is updated, term is set
back to empty, and dropdown back to nonvisible.
this.setState({
selectedBase: event.target.innerHTML,
term: '',
dropdownVisible: false
},
()=>{
// passing state of child up to parent through prop
this.props.onBaseChange(this.state.selectedBase)
// clearing input search on click
document.getElementById("input_search").value = "";
);
}

Having a component re-render on button press in React

I have a simple React component that I'm working on creating right now. Basically, the user can input an ID and when they submit, it will display some information that is in a container. The code looks like so
export default class IDContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
Id: '',
isSubmitted: false
};
}
handleSubmit = (event) => {
this.setState({
isSubmitted: true
});
};
handleChange = (event) => {
this.setState({
Id: event.target.value
});
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}}
>
<Input type={'text'} placeholder={"Enter Id"} value={this.state.Id} onChange={this.handleChange} />
<Button type={'submit'} > Lookup </Button>
</div>
<div>
{this.state.isSubmitted && <DetailsContainer Id={this.state.Id} />}
</div>
</form>
);
}
}
The details container has already been created and just returns some details about the Id that has been passed in. I can show the details of the first Id that I pass in just fine. However, when I enter in another Id and submit the form, the DetailsContainer is not re-rendering and is still showing the details for the older Id. I tried moving it around and adding some logic (I even put the DetailsContainer in my state to see if I can manipulate it that way), but that doesn't seem to be working. I see that there is a shouldComponentUpdate() method, and that seems to be what I need to use, but the guides I saw all place it inside of the DetailsContainer. Anyway for me to have it in IDContainer, or is there an easier way to re-render the DetailsContainer?
I think part of the issue here is that once isSubmitted is set, every change you make to the input will be applied to this.state.Id and passed into DetailsContainer.
I think you'd be better off having one variable for tracking the input state, and variable one for tracking the Id you want to pass into DetailsContainer.
state = { Id: null, inputId: '' };
handleSubmit = (event) => {
this.setState({
Id: this.state.inputId
});
};
handleChange = (event) => {
this.setState({
inputId: event.target.value
});
};
render() {
return (
...
<Input ... value={this.state.inputId} />
...
{this.state.Id !== null ? <DetailsContainer Id={this.state.Id} /> : null}
);
}

Input state not binding onChange on first click

I have declared a state called account_type. I have created an onChange event which changes the value of the state upon clicking the div.
<div
className="price-plan"
value="star"
onClick={() => this.setPlan("star")}
>
The issue is that the account_type state does not get updated the first time I click on the div. It only gets updated when I click on it twice. Is there a way to update the state just by clicking the div. Here's an excerpt from my code showing what I am trying to do
let isRedirect = false;
class PricePlan extends React.Component {
constructor(props) {
super(props);
this.state = {
account_type: "",
renderRedirect: false
};
this.handleChange = this.handleChange.bind(this);
}
// Handle fields change
handleChange = input => e => {
this.setState({ [input]: e.target.value });
};
setPlan(plan) {
this.setState({
account_type: plan
});
console.log(this.state.account_type);
// if (this.state.account_type !== undefined) {
// isRedirect = true;
// }
}
render() {
if (isRedirect) {
return (
<Redirect
to={{
pathname: "/sign-up",
state: { step: 2, account_type: this.state.account_type }
}}
/>
);
}
return (
<div
className="price-plan"
value="star"
onClick={() => this.setPlan("star")}
>
<h3>{this.props.planName}</h3>
<div className="mute price-row">Name</div>
<p className="price">Price</p>
<span className="billed-frequency">Cycle</span>
</div>
);
}
}
As #Jayce444 suggests, setState do not immedeately updates state. So setPlan should look like
setPlan(plan) {
this.setState({
account_type: plan
});
console.log(plan); // Don't expect immediate state change in event handler
}
But you can use this.state.account_type anywhere in render() function. And rendering will happen after this.state.account_type is updated on first click.

I fail to setState my ReactJS state dynamically with a function

I'm trying to set the display of my ReactJS component dynamically.
Basically the game is the following : the user push a button, then the value of the affiliate state is set to true. Allowing to handle the displaying of the buttons.
However my state doesn't changes when I push a button, despite I log it after the change would have occurred. However I have set my state. I wonder what going wrong.
Here my tiny snippet, easy testable and reproducible :
https://codesandbox.io/s/21963yy01y
Here my snippet.js :
export default class App extends React.Component {
state = {
displaySelection: false,
displayCreate: false,
displayUpdate: false,
displayDelete: false,
}
viewSelection = (e) => {
e.preventDefault();
Object.keys(this.state).map((key, index) => {
// console.log("key value: ", key)
console.log("target name: ", e.target.name)
if (key === e.target.name) {
console.log(e.target.name, " set to true =)")
return this.setState({ [e.target.name]: true }, console.log("display state: ", this.state))
} else {
this.setState({ [e.target.name]: false })
}
});
}
render() {
return (
<div className="App">
<button onClick={this.viewSelection}> Launch the Object.keys function =) splay</button>
<div >
<button name="displayCreate" onClick={this.viewSelection}> Create </button>
<button name="displayUpdate" onClick={this.viewSelection}> Update </button>
<button name="displayDelete" onClick={this.viewSelection}> Delete </button>
<button name="displaySelection" onClick={this.viewSelection}> O </button>
</div>
</div>
);
}
}
Why when I push a button the state of this button doesn't change ?
Any hint would be great,
thanks
Found a flaw in your logic. In your else statement in your viewSelection function, you have:
else {
this.setState({ [e.target.name]: false });
}
So in every iteration of the loop, you are setting the target that was clicked to false in state. You can solve that by changing e.target.name to key, like so:
else {
this.setState({ [key]: false });
}
So that way you're only changing the key that isn't the current target. But this is still inefficient because you're still running setState 4 times (1 for each key in state). One more efficient way to achieve what you're looking for is to have an object (essentially a copy of what's in state) with the keys set to false by default. Then take the target from the click and set that to true, like so:
viewSelection = e => {
e.preventDefault();
let newValues = {
displaySelection: false,
displayCreate: false,
displayUpdate: false,
displayDelete: false
};
newValues[e.target.name] = true;
this.setState(newValues);
}

"this" becomes undefined after certain button click (ReactJS)

So, I am trying to save the selected option once the radio button is clicked. It is working fine until I press one of the buttons I have in the following code
{Object.keys(this.state.activeContent).map((key, index) =>
<input type="radio" name="key" value={key}
checked={this.checkOption(this.state.activeContent[key].id)}
onChange={() => this.saveKey_Index(this.state.activeContent[key].id, index)} />
)}
<button onClick={() => this.saveActive(this.state.activeContent)}>Save Active</button>
<button onClick={() => this.runHTML("<html> <title> test </title> </html>")}>Play</button>
The "Play" button gives no error and I can then click from the active list the elements I want. But when I click on "save active" I cannot click on any of the items in my list I get the following error:
https://ibb.co/hpJp48
Here are both of the functions:
Play:
runHTML(htmls) {
console.log(htmls)
this.setState({moved: true})
var template = { htmlContent: this.state.htmlContent };
return (<div dangerouslySetInnerHTML={template} />)
}
Save Active:
saveActive(list) {
this.setState = ({ moved: true })
}
And the error I am getting is from:
saveKey_Index:
saveKey_Index(key, index) {
this.setState({ savedKey: key })
this.setState({ savedIndex: index })
}
And yes I have binded the saveActive and saveKey_Index (the error is from saveKey_Index apparently)
this.saveKey_Index = this.saveKey_Index.bind(this)
this.saveActive = this.saveActive.bind(this)
Why am I getting error after saveActive button and not after play? I can setState in the play button even though it is not binded as well. Why is that?
You're overwriting your component's setState() function with this code:
saveActive(list) {
this.setState = ({ moved: true })
}
There shouldn't be an = there, just
saveActive(list) {
this.setState({ moved: true })
}

Categories