I have data being mapped as a repeater. But I need to isolate the opening function (It's an accordion). I'm still learning my way through React. Basically, the accordions load with the state for open: false Once the ListItem is clicked, the HandleClick function toggles the state to open: true. A simple concept, I just need to isolate it so that it works independently. Whereas right now they all open and close at the same time.
Here is the state in a constructor and function
constructor(props) {
super(props);
this.state = {
open: true,
};
}
handleClick = () => { this.setState({ open: !this.state.open }); };
Here is my mapping script in ReactJS
{LicenseItems.map((item, index) => (
<div key={index}>
<ListItem
divider
button
onClick={this.handleClick}>
<ListItemText primary={<CMLabel>{item.accordion_name}</CMLabel>}/>
</ListItem>
<Collapse
in={!this.state.open}
timeout="auto"
unmountOnExit>
{item.content}
</Collapse>
</div>
))}
The in dictates whether it is open or not per MaterialUI-Next
Thanks in advance guys!
Not very pretty, but something like this should work:
constructor(props) {
super(props);
this.state = {
open: {},
};
}
handleClick = (idx) => {
this.setState(state => ({open: { [idx]: !state.open[idx]} }))
}
// in render
{LicenseItems.map((item, index) => (
<div key={index}>
<ListItem
divider
button
onClick={() => this.handleClick(index)}>
<ListItemText primary={<CMLabel>{item.accordion_name}</CMLabel>}/>
</ListItem>
<Collapse
in={!this.state.open[index]}
timeout="auto"
unmountOnExit>
{item.content}
</Collapse>
</div>
))}
It would be better to create separate Components for that, which have their own open state.
You should create two components for that:
Accordions.js
import React from 'react'
import Accordion from './Accordion'
const Accordions = props => {
return (
props.LicenseItems.map((item, index) => (
<Accordion key={index} item={item} />
))
);
}
export default Accordions;
Accordion.js
import React, { Component } from 'react'
class Accordion extends Component {
constructor(props) {
super(props);
this.state = {
open: true,
};
}
handleClick = () => { this.setState({ open: !this.state.open }); };
render() {
return (
<div>
<ListItem
divider
button
onClick={this.handleClick}>
<ListItemText primary={<CMLabel>{this.props.item.accordion_name}</CMLabel>}/>
</ListItem>
<Collapse
in={!this.state.open}
timeout="auto"
unmountOnExit>
{this.props.item.content}
</Collapse>
</div>
)
}
}
export default Accordion;
Related
react-router-dom v5 and React 16
My loading app component contains:
ReactDOM.render(
<FirebaseContext.Provider value={new Firebase()}>
<BrowserRouter>
<StartApp />
</BrowserRouter>,
</FirebaseContext.Provider>,
document.getElementById("root")
);
I have a route component which contains:
{
path: "/member/:memberId",
component: MemberForm,
layout: "/admin"
},
Admin component:
return (
<>
<div className="main-content" ref="mainContent">
<LoadingComponent loading={this.props.authState.loading}>
<AdminNavbar
{...this.props}
brandText={this.getBrandText(this.props.location.pathname)}
/>
<AuthDetailsProvider>
<Switch>{this.getRoutes(routes)}</Switch>
</AuthDetailsProvider>
<Container fluid>
<AdminFooter />
</Container>
</LoadingComponent>
</div>
</>
)
this.getRoutes in the Switch contains the reference route above.
Now from one of my component pages I can navigate to /member/{memberid} this works fine.
the route loads a component called MemberForm
inside MemberForm I have a row that contains this method:
<Row>
{ this.displayHouseholdMembers() }
</Row>
displayHouseholdMembers = () => {
const householdDetails = this.state.family;
if (householdDetails) {
return householdDetails.map((key, ind) => {
if (key['uid'] != this.state.memberKeyID) {
return (
<Row key={ind} style={{ paddingLeft: '25px', width: '50%'}}>
<Col xs="5">
<Link to={ key['uid'] }>
{ key['first'] + " " + key['last'] }
</Link>
</Col>
<Col xs="4">
{ key['relation'] }
</Col>
<Col xs="3">
<Button
color="primary"
size="sm"
onClick={(e) => this.removeHouseRelation(key)}
>
Remove
</Button>
</Col>
</Row>
);
}
});
}
};
MemberForm:
in componentDidMount I do an firebase call to check for the data pertaining to the user using the uid aka memberId in the URL.
class MemberForm extends React.Component {
constructor(props) {
super(props);
this.state = {
...INITIAL_STATE,
currentOrganization: this.props.orgID,
householdRelation: ['Spouse', 'Child', 'Parent', 'Sibling'],
householdSelected: false,
};
}
componentDidMount() {
let urlPath, personId;
urlPath = "members";
personId = this.props.match.params.memberId;
// if it is a member set to active
this.setState({ statusSelected: "Active" })
this.setState({ memberSaved: true, indiUid: personId });
// this sets visitor date for db
const setVisitorDate = this.readableHumanDate(new Date());
this.setState({ formType: urlPath, visitorDate: setVisitorDate }, () => {
if (personId) {
this.setState({ memberSaved: true, indiUid: personId });
this.getIndividualMemberInDB(
this.state.currentOrganization,
personId,
this.state.formType,
INITIAL_STATE
);
}
});
}
...
return (
<>
<UserHeader first={s.first} last={s.last} />
{/* Page content */}
<Container className="mt--7" fluid>
<Row>
...
<Row>
{ this.displayHouseholdMembers() }
</Row>
</Form>
</CardBody>
) : null}
</Card>
</Col>
</Row>
<Row>
<Col lg="12" style={{ padding: "20px" }}>
<Button
color="primary"
onClick={e => this.submitMember(e)}
size="md"
>
Save Profile
</Button>
{ this.state.indiUid ? (
<Button
color="secondary"
onClick={e => this.disableProfile()}
size="md"
>
Disable Profile
</Button>
) : null }
</Col>
</Row>
</Container>
</>
);
When I click on the Link it shows the url has changed 'members/{new UID appears here}' but the page does not reload. I believe what's going on is that since it's using the same route in essence: path: "/member/:memberId"it doesn't reload the page. How can I get it to go to the same route but with the different memberId?
You are correct that the MemberForm component remains mounted by the router/route when only the path param is updating. Because of this the MailForm component needs to handle prop values changing and re-run any logic depending on the prop value. The componentDidUpdate is the lifecycle method to be used for this.
Abstract the logic into a utility function that can be called from both componentDidMount and componentDidUpdate.
Example:
getData = () => {
const urlPath = "members";
const { memberId } = this.props.match.params;
// this sets visitor date for db
const setVisitorDate = this.readableHumanDate(new Date());
this.setState(
{
// if it is a member set to active
statusSelected: "Active",
memberSaved: true,
indiUid: memberId,
formType: urlPath,
visitorDate: setVisitorDate
},
() => {
if (memberId) {
this.setState({ memberSaved: true, indiUid: memberId });
this.getIndividualMemberInDB(
this.state.currentOrganization,
memberId,
this.state.formType,
INITIAL_STATE
);
}
}
);
}
The lifecycle methods:
componentDidMount() {
this.getData();
}
componentDidUpdate(prevProps) {
if (prevProps.match.params.memberId !== this.props.match.params.memberId) {
this.getData();
}
}
For react-router-dom v6, can you try with simple routing? Create a Test.js with
const Test = ()=> <h1>Test Page</h1>
Then, create a Home.js with
const Home = ()=> <Link to="/test">Test</Link>
Then, add them to route.
<BrowserRouter>
<Routes>
<Route path="/" element={<Home/>} />
<Route path="/test" element={<Test />} />
</Routes>
</BrowserRouter>
Does your component structure look like this? For index route, look more at https://reactrouter.com/docs/en/v6/getting-started/overview.
I am trying to open and close a dialog on a button click from another page/component.
But it is not working on clicking the button.
Any sugegstion what I am missing and doing wrong here with handeling modal.
Thanks in advance.
//TestComponent
class TestConnectDialog extends React.Component {
render() {
const {isOpen, onOk} = this.props;
return (
<Dialog
isopen={this.props.isopen}
onClose={this.props.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Test
</DialogContentText>
</DialogContent>
<DialogActions className="dialog-action">
<Button onClick={this.props.handleClose} className="primary-button">
Ok
</Button>
</DialogActions>
</Dialog>
);
}
};
export default TestConnectDialog;
// Home page
import TestConnectDialog from './TestConnectDialog';
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: false
};
this.handleTestConnectClick = this.handleTestConnectClick.bind(this);
//this.handleCloseDialog = this.handleCloseDialog.bind(this);
}
handleTestConnectClick= () =>{
this.setState({ isOpen: true });
}
render() {
const {isOpen, onOk} = this.props;
return (
<div className="section">
<Button className="connect-test-button"
onClick={this.handleTestConnectClick}>
Test
</Button>
<TestConnectDialog isOpen={this.state.isOpen} />
</div>
);
}
};
export default HomePage;
Your prop name is spelled incorrectly, it should be this.props.isOpen also a quick little tip, it is possible to use just one function for opening/closing the modal.
Something like this will work:
handleTestConnectClick = () => {
this.setState(prevState => ({
...prevState,
isOpen: !prevState.isOpen
}));
}
here we use our previous state and with the ! operator we switch from true to false and vice versa
Update 2.0:
After taking a closer look at the Material UI documentation, I noticed that your dialog prop for setting the modal visibility is wrong. It should be open instead of isOpen.
import TestConnectDialog from './TestConnectDialog';
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: false
};
//this.handleTestConnectClick = this.handleTestConnectClick.bind(this);
//this.handleCloseDialog = this.handleCloseDialog.bind(this);
// when using arrow functions you don't need to bind the this keyword
}
handleTestConnectClick = () => {
this.setState(prevState => ({
...prevState,
isOpen: !prevState.isOpen
}));
}
render() {
return (
<div className="section">
<Button className="connect-test-button"
// onClick={this.handleTestConnectClick}>
// change the onClick to the one below
onClick={ () => this.handleTestConnectClick() }
Test
</Button>
<TestConnectDialog isOpen={this.state.isOpen} handleTestConnectClick={this.handleTestConnectClick}/>
</div>
);
}
};
export default HomePage;
In TestConnectDialog component:
class TestConnectDialog extends React.Component {
render() {
return (
<Dialog
open={this.props.isOpen}
onClose={this.props.handleTestConnectClick}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Test
</DialogContentText>
</DialogContent>
<DialogActions className="dialog-action">
<Button onClick={this.props.handleTestConnectClick} className="primary-button">
Ok
</Button>
</DialogActions>
</Dialog>
);
}
};
export default TestConnectDialog;
You're passing the props <TestConnectDialog isOpen={this.state.isOpen} /> but trying to read it with isopen={this.props.isopen}.
Change your code to this: isopen={this.props.isOpen}
Update TestComponent component as given
class TestConnectDialog extends React.Component {
render() {
const {isOpen, onOk} = this.props;
return (
<Dialog
isopen={isOpen}
onClose={this.props.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Test
</DialogContentText>
</DialogContent>
<DialogActions className="dialog-action">
<Button onClick={this.props.handleClose} className="primary-button">
Ok
</Button>
</DialogActions>
</Dialog>
);
}
};
export default TestConnectDialog;
In the homepage component why is isOpen destructured from the prop and initialised in state. You have to use one, using both is confusing, you are working with that on the state but passing the one from the prop
I have a Select Form Child Component from which the user can choose multiple options. Every time the user makes a choice, a function handleChange is executed which calls the function changeExport from parent(passed as a prop to the child). changeExport then updates the parent state and handleChange finishes by updating the child state. The problem is that if the parent state is updated, the child state is not, but if I comment out the line which updates the parent state, child state is updated just fine.
This is the Parent.
class ExtendedTable extends React.Component {
constructor(props) {
super(props)
// columnJSON el format is { title: str, field: str, export: bool }
this.state = { dataJSON: [], columnJSON: [] }
this.changeExport = this.changeExport.bind(this)
}
changeExport(titles){
const newColumnJSON = JSON.parse(JSON.stringify(this.state.columnJSON));
newColumnJSON.forEach(col => {
if (titles.indexOf(col.title) >= 0) {
col.export = true
}
else {
col.export = false
}
})
this.setState({ columnJSON: newColumnJSON })
}
render(){return(
....
<MultipleSelect names={this.state.columnJSON.map(el=>el.title)} export={this.changeExport} />
)}
This is the child.
class MultipleSelect extends React.Component {
constructor(props){
super(props)
this.state = {
names:this.props.names,
column:[]}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event){
const arr = event.target.value.slice()
this.setState({column:arr})
this.props.export(arr)
}
render() { return(
<div>
<FormControl>
<InputLabel >Tag</InputLabel>
<Select
multiple
value={this.state.column}
onChange={this.handleChange}
input={<Input />}
renderValue={selected => selected.join(', ')}
MenuProps={MenuProps}
>
{this.state.names.map(col => (
<MenuItem key={col} value={col}>
<Checkbox checked={
this.state.column.indexOf(col) > -1}/>
<ListItemText primary={col} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
)};
}
What you are doing here—copying props to state—is warned against in the React documentation for this reason.
The linked page offers a number of alternatives. In your case I think you would be best served by making MultipleSelect a controlled component by eliminating state entirely and relying solely on props passed in. This might look something like this:
class MultipleSelect extends React.Component {
render() {
return (
<div>
<FormControl>
<InputLabel>Tag</InputLabel>
<Select
multiple
value={this.props.selected}
onChange={this.props.handleChange}
input={<Input />}
renderValue={selected => selected.join(", ")}
MenuProps={MenuProps}
>
{this.props.options.map(col => (
<MenuItem key={col} value={col}>
<Checkbox checked={this.props.selected.indexOf(col) > -1} />
<ListItemText primary={col} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
);
}
}
I have started learning react native 2 days back only. I am using list item component from Native Base UI framework.
According to their docs and examples to catch a click event on ListItem you need to add onPress and button option to the ListItem. But in my case its not working.
I have another element with also tracks click event, it works fine, but list element isn't catching click event.
Strange this is that if I trigger a alert, it works
<List button onPress={() => { Alert.alert('Item got clicked!') } }>
Below id my complete code
import React from 'react';
import {
Content,
List,
ListItem,
Body,
Thumbnail,
Text,
Badge,
View
} from 'native-base';
import { ActivityIndicator, TouchableHighlight, TouchableOpacity, Alert } from 'react-native';
export default class Questions extends React.Component{
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
Alert.alert("I am clicked");
// Call method from parent
this.props.onPress();
}
render() {
var items = this.props.items;
return (
<Content>
<List button onPress={() => { this.handleClick } }>
{Object.keys(items).map(function(eachQuestion) {
return (
<ListItem avatar key={items[eachQuestion].id} button onPress={() => { this.handleClick } } >
<Body>
<Text>{items[eachQuestion].question}</Text>
</Body>
</ListItem>
)
})}
</List>
<TouchableOpacity onPress={this.handleClick}>
<View><Text>Click me</Text></View>
</TouchableOpacity>
</Content>
);
}
}
Edit 1
render() {
var questions = {
"1" : "James",
"2" : "Smith",
"3" : "Doe",
"4" : "Smith"
};
return (
<Container>
<Content>
<List>
{Object.keys(questions).map(function(key) {
return (<ListItem button={true} onPress={this.handleClick}>
<Text>{questions[key]}</Text>
</ListItem>
)
})}
</List>
</Content>
</Container>
);
}
** Final Solution **
handleClick(){
Alert.alert("I got clicked");
}
render() {
var questions = this.props.questions;
return (
<Content>
<List>
{Object.keys(questions).map((eachQuestion) => {
return (
<ListItem key={questions[eachQuestion].id} button={true} onPress={this.handleClick} >
<Body>
<Text>{questions[eachQuestion].question}</Text>
</Body>
</ListItem>
)
})}
</List>
</Content>
);
}
Two errors:
You should brush up on your ES6 arrow function expressions. You aren't calling your handleClick function which is why nothing is happening vs your Alert example where it does work (since you are actually doing something).
You don't define the value for the button prop. The docs say that there is no default value, so it's good practice to define it as true or false.
So to fix your code, you should define your props for ListItem like so:
button={true}
onPress={() => { this.handleClick() }}
OR to make it shorter:
button={true}
onPress={this.handleClick}
I'm also not sure why you are defining button and onPress props on your List component since it's the ListItems that you are trying to click, not the entire List itself. But since that isn't part of the question, I won't address that.
Full example of working code:
import React, { Component } from 'react';
import { Container, Content, List, ListItem, Text } from 'native-base';
import { Alert } from 'react-native';
export default class App extends Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
Alert.alert("I am clicked");
// Call method from parent
//this.props.onPress();
}
render() {
return (
<Container>
<Content>
<List>
<ListItem button={true} onPress={this.handleClick}>
<Text>Simon Mignolet</Text>
</ListItem>
<ListItem button={true} onPress={() => { this.handleClick() }}>
<Text>Nathaniel Clyne</Text>
</ListItem>
<ListItem button={true} onPress={this.handleClick}>
<Text>Dejan Lovren</Text>
</ListItem>
</List>
</Content>
</Container>
);
}
}
I am very new at React and Redux both, I have only been using both for about 2 - 3 weeks to develop an alpha version of an application.
Though most of the tutorials on using Redux with React seemed to be pretty complicated I found one that allowed me to get some quick code down to try very simple scenarios within my application.
The main problem I seem to face at the moment is: I want to click on an image of and show the details of said property on another page (routed to using react-router, passing id in the path - to clarify in the current code i am using the hardcoded id of 22 an the id is not passed in the path yet). I thought it would as straight forward as clicking on the app then in either the constructor or componentWillMount method I could call this.props.foo(id) and then get the property using this.props.store.foo but it seems as though the store is not updated at that time. But if i called this.props.foo(id) in the handleClick method of the page before redirecting then it would work, but on refresh the store is back to default and causes an error.
I am just wondering if I am just taking a completely wrong approach to this.. or just missing something.
The code may be too much, just let me know if I should trim it down...
Functions to look for are the:
handleImageClick() - > Results.js
constructor() - > BuyDetails.js
Code:
Index.js
let state = {
results: [],
selectedState:{},
};
let reducer = (state, action) => {
console.log("in reducer" + action.type);
switch (action.type) {
case 'ADD_RESULTS':
console.log("in reducer add");
console.log("in reducer results = " + action.results);
var newState = Object.assign({}, state)
newState.results = action.results
console.log("in reducer add " + JSON.stringify(newState))
return newState
case 'GET_RESULTS':
console.log("in reducer get state = " + state.results[0].id);
var newState = Object.assign({}, state)
for (var result of state.results){
if (result.id === action.id){
console.log(result.img)
newState.selectedState = result
console.log(newState.selectedState.location.address)
}
}
console.log(newState.selectedState.location.address)
console.log(JSON.stringify(newState));
return newState
default:
return state
}
}
let store = createStore(reducer, state)
let mapStateToProps = state => ({
store: state
})
let mapDispatchToProps = dispatch => ({
addResults: (results) => dispatch({type: 'ADD_RESULTS', results:results}),
getSelectedResult: (id) => dispatch({type: 'GET_RESULTS', id:id}),
})
const ConnectedAppComponent = connect(
mapStateToProps, mapDispatchToProps
)(App)
const ConnectedResultsComponent = connect(
mapStateToProps, mapDispatchToProps
)(Results)
const ConnectedBuyDetailsComponent = connect(
mapStateToProps, mapDispatchToProps
)(BuyDetails)
ReactDOM.render(
<Provider store={store}>
<Router history={hashHistory}>
<Route path="/" component={ConnectedAppComponent}/>
{/* add the routes here */}
<Route path="/results" component={ConnectedResultsComponent}/>
<Route path="/buyDetails" component={ConnectedBuyDetailsComponent}/>
</Router>
</Provider>,
document.getElementById('root')
);
Results.js
class Results extends Component{
constructor(props) {
super(props);
this.state = {open: true, openProfile:false, anchorEl: null,dataSet:this.props.store.results};
console.log(this.state.dataSet.length)
console.log(this.state.dataSet[0].img)
}
handleTouchTap = (event) => {
// This prevents ghost click.
console.log("touch tap");
event.preventDefault();
const tempState = this.state;
tempState.openProfile = true
tempState.anchorEl = event.currentTarget
this.setState(tempState)
/*this.setState({
openProfile: true,
anchorEl: event.currentTarget,
});*/
};
handleRequestClose = () => {
const tempState = this.state;
tempState.openProfile = false
tempState.anchorEl = null
this.setState(tempState)
/*this.setState({
openProfile: false,
});*/
};
handleToggle = () => this.setState({open: !this.state.open});
handleImageClick(){
//This is where i could be doing this.props.getSelectedResult(22); and it would work but causes issues on refresh
const path = `/buyDetails`
this.context.router.push(path)
}
render() {
return <MuiThemeProvider>
<div className="Results" id="Results" style={styles}>
<div>
<Toolbar style={appBarStyle}>
<IconButton iconClassName="material-icons"
style={{bottom: '0',height:'auto'}}
onClick={this.handleToggle}>
menu
{/*<FontIcon className="material-icons" color={grey900} onClick={this.handleToggle}>menu</FontIcon>*/}
</IconButton>
<ToolbarGroup style={groupStyle}>
<ToolbarSeparator style={seperatorMargin}/>
<FontIcon style={searchIconnStyle} className="material-icons">search</FontIcon>
<ToolBarSearchField />
</ToolbarGroup>
<ToolbarGroup>
<ToolbarSeparator style={residentialSeperatorStyle}/>
<FlatButton label="Residential" style={selectedToolBarButtonStyle}/>
<ToolbarSeparator style={seperatorStyle}/>
<FlatButton label="Commerical" style={toolBarButtonStyle}/>
<ToolbarSeparator style={seperatorStyle}/>
<FlatButton label="JoellyR" style={toolBarButtonStyle} onTouchTap={this.handleTouchTap}/>
<Popover open={this.state.openProfile}
anchorEl={this.state.anchorEl}
anchorOrigin={{horizontal: 'right', vertical: 'bottom'}}
targetOrigin={{horizontal: 'right', vertical: 'top'}}
onRequestClose={this.handleRequestClose}>
<MenuItem value={1} primaryText="Price Range" />
<MenuItem value={2} primaryText="values" />
</Popover>
</ToolbarGroup>
</Toolbar>
<ToolBarFilterFields fieldNames={['Buy', 'Sell', 'Rent', 'Businesses', 'Mortgages']} displaySeperator={false}/>
</div>
<Drawer
open={this.state.open}
containerStyle={{top:'inherit', boxShadow:'(0,0,0,0)', border:'0px', borderRight:'1px solid', borderColor: 'rgba(0,0,0,0.3)'}}>
</Drawer>
<div style={this.state.open ? drawerExpanded : drawerCollapsed }>
<Paper style={paperStyle}>
<ToolBarFilterFields fieldNames={['Filters', 'Price', 'Bath', 'Beds', 'Type', 'Style']} displaySeperator={true}/>
<ResultGridList dataSet={this.state.dataSet} onClick = {() => this.handleImageClick()}/>
</Paper>
</div>
</div>
</MuiThemeProvider>
}
}
Results.contextTypes = {
router: React.PropTypes.object
}
export default Results;
BuyDetails.js
class BuyDetails extends Component{
constructor(props) {
super(props);
//dispatching the action here
this.props.getSelectedResult(22);
//getting the selected object from the props.state ... but it will still be = {}
this.state = {open: true, openProfile:false, anchorEl: null,data:this.props.store.selectedState};
}
componentWillMount() {
}
handleTouchTap = (event) => {
console.log('in buy detail: ' + JSON.stringify(this.props.store.selectedState) + JSON.stringify(this.props.store.results));
// This prevents ghost click.
console.log("touch tap2");
event.preventDefault();
const tempState = this.state;
tempState.openProfile = true
tempState.anchorEl = event.currentTarget
this.setState(tempState)
/*this.setState({
openProfile: true,
anchorEl: event.currentTarget,
});*/
};
handleRequestClose = () => {
const tempState = this.state;
tempState.openProfile = false
tempState.anchorEl = null
this.setState(tempState)
/*this.setState({
openProfile: false,
});*/
};
handleToggle = () => this.setState({open: !this.state.open});
render() {
return <MuiThemeProvider>
<div className="BuyDetails" id="BuyDetails" style={styles}>
<div>
<Toolbar style={appBarStyle}>
<IconButton iconClassName="material-icons"
style={{bottom: '0',height:'auto'}}
onClick={this.handleToggle}>
menu
{/*<FontIcon className="material-icons" color={grey900} onClick={this.handleToggle}>menu</FontIcon>*/}
</IconButton>
<ToolbarGroup style={groupStyle}>
<ToolbarSeparator style={seperatorMargin}/>
<FontIcon style={searchIconnStyle} className="material-icons">search</FontIcon>
<ToolBarSearchField />
</ToolbarGroup>
<ToolbarGroup>
<ToolbarSeparator style={residentialSeperatorStyle}/>
<FlatButton label="Residential" style={selectedToolBarButtonStyle}/>
<ToolbarSeparator style={seperatorStyle}/>
<FlatButton label="Commerical" style={toolBarButtonStyle}/>
<ToolbarSeparator style={seperatorStyle}/>
<FlatButton label="JoellyR" style={toolBarButtonStyle} onTouchTap={this.handleTouchTap}/>
<Popover open={this.state.openProfile}
anchorEl={this.state.anchorEl}
anchorOrigin={{horizontal: 'right', vertical: 'bottom'}}
targetOrigin={{horizontal: 'right', vertical: 'top'}}
onRequestClose={this.handleRequestClose}>
<MenuItem value={1} primaryText="Price Range" />
<MenuItem value={2} primaryText="values" />
</Popover>
</ToolbarGroup>
</Toolbar>
</div>
<Drawer
open={this.state.open}
containerStyle={{top:'inherit', boxShadow:'(0,0,0,0)', border:'0px', borderRight:'1px solid', borderColor: 'rgba(0,0,0,0.3)'}}>
</Drawer>
<div style={this.state.open ? drawerExpanded : drawerCollapsed }>
<Paper style={paperStyle}>
<BuyDetailGridList data={this.props.store.selectedState}/>
</Paper>
</div>
</div>
</MuiThemeProvider>
}
}
function isEmpty(obj) {
for(var key in obj) {
if(obj.hasOwnProperty(key))
return false;
}
return true;
}
export default BuyDetails;
Thanks Everyone... In Advance :)
+++UPDATE - Still not working+++
Here is the code for another approach i tried which was just calling the dispatch in componentWillMount() then just passing this.props.store.selectedState directly to the child component.
BuyDetails.js
class BuyDetails extends Component{
constructor(props) {
super(props);
this.state = {open: true, openProfile:false, anchorEl: null,data:{}};
//console.log('in buy details '+ JSON.stringify(this.state.data));
}
componentWillMount() {
//dispatching the action here... it is still this.props.store.selectedState is still = {}
this.props.getSelectedResult(22);
}
handleTouchTap = (event) => {
console.log('in buy detail: ' + JSON.stringify(this.props.store.selectedState) + JSON.stringify(this.props.store.results));
// This prevents ghost click.
console.log("touch tap2");
event.preventDefault();
const tempState = this.state;
tempState.openProfile = true
tempState.anchorEl = event.currentTarget
this.setState(tempState)
/*this.setState({
openProfile: true,
anchorEl: event.currentTarget,
});*/
};
handleRequestClose = () => {
const tempState = this.state;
tempState.openProfile = false
tempState.anchorEl = null
this.setState(tempState)
/*this.setState({
openProfile: false,
});*/
};
handleToggle = () => this.setState({open: !this.state.open});
render() {
return <MuiThemeProvider>
<div className="BuyDetails" id="BuyDetails" style={styles}>
<div>
<Toolbar style={appBarStyle}>
<IconButton iconClassName="material-icons"
style={{bottom: '0',height:'auto'}}
onClick={this.handleToggle}>
menu
{/*<FontIcon className="material-icons" color={grey900} onClick={this.handleToggle}>menu</FontIcon>*/}
</IconButton>
<ToolbarGroup style={groupStyle}>
<ToolbarSeparator style={seperatorMargin}/>
<FontIcon style={searchIconnStyle} className="material-icons">search</FontIcon>
<ToolBarSearchField />
</ToolbarGroup>
<ToolbarGroup>
<ToolbarSeparator style={residentialSeperatorStyle}/>
<FlatButton label="Residential" style={selectedToolBarButtonStyle}/>
<ToolbarSeparator style={seperatorStyle}/>
<FlatButton label="Commerical" style={toolBarButtonStyle}/>
<ToolbarSeparator style={seperatorStyle}/>
<FlatButton label="JoellyR" style={toolBarButtonStyle} onTouchTap={this.handleTouchTap}/>
<Popover open={this.state.openProfile}
anchorEl={this.state.anchorEl}
anchorOrigin={{horizontal: 'right', vertical: 'bottom'}}
targetOrigin={{horizontal: 'right', vertical: 'top'}}
onRequestClose={this.handleRequestClose}>
<MenuItem value={1} primaryText="Price Range" />
<MenuItem value={2} primaryText="values" />
</Popover>
</ToolbarGroup>
</Toolbar>
</div>
<Drawer
open={this.state.open}
containerStyle={{top:'inherit', boxShadow:'(0,0,0,0)', border:'0px', borderRight:'1px solid', borderColor: 'rgba(0,0,0,0.3)'}}>
</Drawer>
<div style={this.state.open ? drawerExpanded : drawerCollapsed }>
<Paper style={paperStyle}>
<BuyDetailGridList data={this.props.store.selectedState}/>
</Paper>
</div>
</div>
</MuiThemeProvider>
}
}
function isEmpty(obj) {
for(var key in obj) {
if(obj.hasOwnProperty(key))
return false;
}
return true;
}
export default BuyDetails;
I wouldn't fetch the item in the details component, at least not explicitly.
Consider:
A details component:
class DetailsComponent extends React.Component {
// the item is now available in props.item
}
function mapStateToProps(state, props) {
return {
item: state.getSelectedItem()
};
}
export default connect(mapStateToProps)(DetailsComponent);
A list component:
class ListComponent extends React.Component {
...
onImageClick = (item) => {
this.props.setSelectedItem(item);
}
...
}
This relies on set/getSelectedItem actions which set some relevant state. The details component will automatically grab the selected item when it's mounted.
Another thing to consider would be, if the two components were being rendered simultaneously (in a list/detail style UI, for example), would be to lift the selected state up into the parent state (parent of both components).
class ParentComponent extends React.Component {
...
onItemSelected = (item) => {
this.setState({ selectedItem: item });
}
render() {
return (
<ListComponent onItemSelected={ this.onItemSelected }/>
<DetailsComponent item={ this.state.selectedItem }/>
);
}
}
That all said, you posted a lot of code and it's a little hard to tell what's going on. Hopefully something I've written above helps with your issue.