I'm building a react/redux app and using a ux library called Grommet in the front end. I have the app set up such that I have a series of forms contained within a set of accordions on the page. Here's a whittled downed version containing only one accordion tab:
handleCpuChange(event) {
console.log(event.target)
this.props.updateStore(
{'general': {'cpus': event.target.value} }
)
}
<Accordion>
<AccordionPanel heading="General">
<Box>
<FormFields>
<FormField label='CPUs'>
<NumberInput
value={this.props.form.formData.general.cpus}
onChange={this.handleCpuChange.bind(this)}/>
</FormField>
<FormField label='Ram'>
<NumberInput
defaultValue={this.props.form.formData.general.ram}
onChange={this.handleCpuChange.bind(this)}/>
</FormField>
</FormFields>
</Box>
</AccordionPanel>
</Accordion>
- All of this works fine. The problem is that when I call the handleCpuChange function is called my state/store value gets updated - but my the actual 'value' or 'defaultValue' fields stay the same. For the most part this is no problem but if I close and reopen the accordion the values in those fields resets to the defaults/values supplied through props. I figured that a nice way around this is to remap the state to props whenever the accordion opens or closes that way the actual value updates - but I'm not sure how to do this without reloading the entire page.
Related
This question already has answers here:
How to prevent buttons from submitting forms
(20 answers)
Closed 9 months ago.
I am very puzzled by this. I have a modal that opens up to allow a user to fill out information. I have an add button that adds a new row to store and renders a new row. But I realized that even if I am only console logging, clicking that button causes the whole page/tab to do a full refresh. Why is this happening? I was initially checking for props or state changes but cannot figure it out.
handleAddNewRow = () => {
console.log('adding new row')
// this.setState(...) -- this is commented out due to make sure that setting state is not the problem
}
<FormSection>
{this.state.stores.map(store, index) => (
<div key={store.id}>
<div>
<h4>
Choose Store
</h4>
<Dropdown options={storeOptions}>
</Dropdown>
</div>
<TextInput />
<TextInput />
</div>
)}
<div>
<button onClick={this.handleAddNewStore}>
Add New Store
</button>
</div>
</FormSection>
I thought that the setting state was the issue but I commented that out. I tried wrapping the component in a React.memo() as well. Thank you.
It probably causes form sending. You should pass in your onClick callback event parameter and call event.preventDefault() method.
My aim is to delete the button, I have just clicked. I understand there may be numerous ways such as creating a deleteButton component, and setting the state appropriately.
However, my return function in the main App component will also render another button (this I can do), but I think this may add to the complexity.
I'm currently struggling to pin-point the ideal solution, so please help.
Okay, so I've managed to solve my question, although I'm sure there's other ways too.
To further clarify...
I had a form which I wished to render, when clicking on a 'Create' Button.
At the same time, I wished to remove the 'Create' button, once clicked.
The end result is to only display the form and nest a new button in the return function.
1) Set the initial state of the form to false:
this.state = {
displayForm: false,
}
2) Then use setState within the displayForm function to allow for the change in state, once the button is clicked:
displayForm(){
this.setState({
displayForm: !this.state.displayForm {/* true */}
})
}
3) set a style object within the render function, such as:
render() {
const btnStyle = {
display: 'block',
} ...
4) Use an IF statement to change the display style of the button if the form has been rendered
if(this.state.displayForm){
btnStyle.display = 'none'
}
5) Now, within the return function, use your JSX tags appropriately and call the function onClick, as well as the style to be applied.
<Button
style={btnStyle}
onClick={() => {
this.displayForm()
}}>Create</button>
{this.state.displayForm && ([
<Form />,
<br />,
<Button>Add Schema</Button>,
])}
NOTE: the < Form /> and < Button /> components have been imported and added here.
So, once the 'Create' button has been clicked, the form displays (true), and thereby the 'Create' button disappears from the Virtual DOM. I've also nested another (new) button as intended, underneath the form.
I have built a react application which shows items from JSON file, it consists of 4 main components, Items.js which created the item itself alongside its props (title and image), Itemlist.js which shows items from items.js and other functions.
MenuCat maps and shows each category from the json, and whenever the category is clicked it returns a number(props) to Itemlist.js adding it to the mapping function of items as ( children[{props here}].children[]....) so that it maps all items of each clicked category by using its json index.
Whenever an item is clicked, it shows more JSON properties such as promos inside a pop up called drawer, the content of this pop up is from Modifiers.js.
I need a function similar to MenuCat.js's category clicks but with items instead, where it shows the exact children of the item (e.g Burger 1 shows desert promo 1 on click, and burger 2 shows desert promo 2). The way its set up now, it only shows desert promo 1 for all the items.
Sandbox (current view on app.js): https://codesandbox.io/embed/8j5mmrjk2?fontsize=14&moduleview=1
One problem I noticed with your components was that you were passing the key attribute. This is anti-pattern as React does not pass down ref or key props.
If you need to access the same value within the child component, you should pass it as a different prop (ex: <ListItemWrapper key={result.id} id={result.id} />).
Just pass it down as a different attribute such as myKey.
I've done some other tweaks which you can check in the forked sandbox. Most notably, I added a state value to track the child index that was clicked.
this.state = {
itemSelected: 0
}
...
{items.children[selected].children[itemSelected].children.map(
(item, index) => (
<Modifiers
key={index}
title={item.name}
myKey={index}
childp={item.children[index].name}
>
{" "}
</Modifiers>
)
)}
I'm new to react-native so this.setstate method is not predictable for me.
I'm selecting a list of Venue on dropdown 1
according to the venue , the number of available days must be shown as options on the second dropdown.
and similarly according to the second one i have to set timeslots avaiable on the third dropdown
the 2nd to 3rd dropdown works fine for me
but when i select the venue on the first dropdown the 2nd one does not updates. this .setstate is working late there
if i select the venue once more the previously selected days loads not the current one. like setstate method is lagging one step behind
Must be the way i wrote the code ,
I am open to corrections, new structure of coding , anything
but very much in need to get this work
onVenueSelect(index,value){
var props=this.props;
console.log('On venue Select................................')
console.log('index'+index)
console.log('value'+value)
console.log(this.state.venue_id_array[index])
props.getFixtureSlots(this.state.venue_id_array[index], this.state.game_type, this.state.game);
this.setState({selected_venue_id:this.state.venue_id_array[index]})
var days=[];
var timeslots=props.GETFIXTURETIME.timeslot;
for(var i in timeslots){
days.push(timeslots[i].day_of_week);
}
this.setDay_array(days);
this.refs.modal_dayselect.select(-1);
this.setState({selected_venue:value});
}
onDaySelect(index,value){
this.refs.modal_hrsselect.select(-1);
this.props.getFixtureSlots(this.state.selected_venue_id, this.state.game_type, this.state.game);
var props=this.props;
this.setState({selected_day_no:this.state.day_no_array[index]})
console.log(this.state.day_no_array[index])
this.setState({selected_day:value})
}
render_center_selection(){
return(
this.props.selecteddays_array.map((a, i) => {
return( <View key={i} style={{ height:40, borderBottomWidth:2, borderBottomColor: '#ededed' }}>{
<View style={{flexDirection:'column'}}>
<View style={{flexDirection:'row'}}>
<ModalDropdown
style={styles.selection}
defaultValue='Venue'
textStyle={{width:200,fontSize:20,textAlign:'center',color: '#7070D8'}}
dropdownStyle={styles.dropdownstyle}
dropdownTextStyle={{width:350,fontSize:20,textAlign:'center',backgroundColor: '#FDD60B',}}
options={this.state.venue_name_array}
onSelect={(index,value)=>{this.onVenueSelect(index,value)}}/>
<ModalDropdown
ref="modal_dayselect"
style={styles.dayselection}
defaultValue='Day'
textStyle={{width:50,fontSize:15,textAlign:'center',color: '#7070D8'}}
dropdownStyle={styles.daydropdownstyle}
dropdownTextStyle={{width:50,fontSize:15,textAlign:'center',backgroundColor: '#FDD60B',color: '#7070D8'}}
options={this.state.day_array}
onSelect={(index,value)=>{this.onDaySelect(index,value)}}/>
<ModalDropdown
ref="modal_hrsselect"
style={styles.dayselection}
defaultValue='HRS'
textStyle={{width:50,fontSize:15,textAlign:'center',color: '#7070D8'}}
dropdownStyle={styles.daydropdownstyle}
dropdownTextStyle={{width:50,fontSize:15,textAlign:'center',backgroundColor: '#FDD60B',color: '#7070D8'}}
options={this.state.hrs_array}
onSelect={(index,value)=>{this.setState({selected_hr:value})}}/>
</View>
</View>
}</View>);
})
);
}
First thing you have to do is to remove all console.log statements from your code. It really helpful but slows down the app rendering/refreshing rate.
Second thing and the most important thing is to consolidate state setting calls. ie, you only need one setState call inside one action. For every setState call the app re-renders the parts which uses that changed state. So, update multiple states at once otherwise it will not be detected by the react.
very new to react. you can say I have not yet started to think like React.
here is the problem:
<div>
<DropDown> </DropDown>
<Panel> </Panel>
</div>
In the dropdown, I select a value. Store it in state, as something as , currentLocation.
Then I go to Panel, hit a button, and I want to open a modal. When i open a modal, I need to pass the currentLocation to that model.
I can pass in arbitrary value to modal, but I cannot figure out a way to get the currently selected item from DropDown.
How do I get the value of the currently selected item to the Panel?
Am I even making sense?
When you call the setState in the dropdown that will force an update of the page.
Then if you call this.state in your component you should have the value you need there.
You should go over the basic tutorials to grasp the react basics.
But it goes like this:
getInitialState: function() {
return {
myVar: ''
//set your variables here
//getInitialState will get called before the component gets mounted
};
},
myCustomFunction: function(newVariable) {
this.setState({
myVar: newVariable
});
},
render: function() {
return (
<div>
<input
onChange={this.myCustomFunction}
/>
<MyCustomComponent myProp={this.state.myVar}/>
//everytime the state changes MyCustomComponent will have that new value as a prop
</div>
);
}
There is a lot of ambiguity in your question but I'll try for the simplest case.
You have a Panel component and a Dropdown component.
You want to the Panel to have access to a value that was set when the Dropdown was used.
Solution: When the Dropdown is actuated, it creates an Action that Stores the selected value.
When the modal button in the Panel is actuated, it creates an Action that requires the DropDownStore. Then it decides what to do based on that value.
The pattern I am loosely describing is known Facebook's Flux architecture which is basically just a more specific application architecture for React applications similar to pub/sub or an event bus.