Please I am currently displaying a list of business from a businesses array. Each business has its unique id. I am displaying the businesses by mapping my business array through a react "Business Card Component" This card is a small materialize card that shows few properties of the business.
The API endpoint to get the full details of a particular businesses is < url/businesses/id >
On each business card, I have a button which says "visit", such that when a user clicks the button, he send request to url/businesses/id, and when the request is successful, I will update the state using redux and render the BusinessProfile page that will render the business particulars.
My approach is to concatenate url/businesses/ with the id of business and send the request.
But I dont know how to access the business id from the "visit" button.
const FoundBusinesses = realBusiness.map((eachBusiness, index) => {
return (
<BusinessCard key={index}
business={eachBusiness}
businessPic={profilePicture}
handleClick={this.handleClick}
/>
)
})
I will appreciate any help please
handleClick={() => {this.handleClick(business.id)}
This link is also good, it shows you how you can send your data as a parameter to your click handler. https://medium.freecodecamp.org/reactjs-pass-parameters-to-event-handlers-ca1f5c422b9
If the 'visit' button is inside BusinessCard, you should already have the id inside eachBusiness.businessId, correct? And if I am understanding your question correctly, you can pass it to your handleclick function and change the URL. The below code is using history from react-router to change the url.
With an arrow function inside the button
HandleClick:
handleClick(businessId) {
this.props.history.push(`url/businesses/${businessId}`)
}
Inside BusinessCard:
<button onClick={() => this.props.handleClick(this.props.business.businessId)}>
See business info
</button>
HandleClick will use that particular Id when it executes so it pushes to the correct URL.
With a closure
You can also do the same with a closure for cleaner function call:
handleClick(businessId) {
return () => this.props.history.push(`url/businesses/${businessId}`)
}
Inside BusinessCard:
<button onClick={this.props.handleClick(this.props.business.businessId)}>
See business info
</button>
Related
I have some list in my application - there are screens like
ListScreen
CreateItemScreen
EditItemScreen
So firstly user goes to ListScreen, he can click "add item" and goes to CreateItemScreen. If he wants to delete item he needs to go to EditItemScreen and there is placed "Delete" button.
Items are stored in redux state - so when user creates item it's gonna be stored in redux. If user edits it - it's gonna be edited in redux. If he wants to delete item it needs to be deleted in redux.
When user click "Delete" system deletes it and redirect user back to ListScreen. Button system triggers delete item redux action, item is deleted and component is re-rendering - because redux state was changes so component's gonna be re-rendered. After it redirect is triggered(react-router-dom). But before redirect is triggered error appear. Because item is already deleted and screen is trying to take some item props.
Component looks like:
export const EditItemScreen = ({}) => {
const { itemId } = useRouteMatch().params;
const item = useSelector(getItemSelector(itemId));
const history = useHistory();
const dispatch = useDispatch();
const handleDeleteClick = () => {
history.replace('listPath');
dispatch(deleteItem(itemId));
};
return (
<div>
<h1>{item.title}</h1>
<form>...form</form>
<div>
<button onClick={handleDeleteClick}>
Delete
</button>
</div>
</div>
);
};
When user click "Delete" there is error which tells me that can't get title from undefined(because item is already deleted).
Can I prevent this last re-rendering? Just execute redirect before delete item and don't go back to this screen and don't re-render it?
Have you tried to do the dispatch before returning to the previous screen?
dispatch(deleteItem(itemId));
history.replace('listPath');
You want to leave the current component once everything is done so i think this should work.
You can try conditional rendering based on whether item.title is defined.
I am using react fontawesome in my project. Under the render function of my component I have the following which maps a school onto the page and then I want a button with an edit icon to perform an action. My code for the button looks as below:
{ this.state.myschools.map( (school) => (
<Row key={school.id}>
<Col><p>{school.name}</p></Col>
{ school.deaths.length > 0 ? <Col md="2"><button id={school.id} className="likelink" onClick={this.goToSchoolDeathList}>View Deaths</button></Col> : <Col md="2"></Col> }
<Col><button id={school.id} onClick={this.editSchool}><FontAwesomeIcon icon={faEdit} /></button></Col>
</Row>
))}
The editSchool function is as:
editSchool(e) {
console.log("School Id");
console.log(e.target.id);
}
If I click on the empty space around the font awesome icon then the id is logged to the console. If I only click on the area where the icon exits then the id is not logged. I want the user to be able to click on any part of the button including the fa icon and to capture the school id.
I have tried adding the onClick event and the id attribute to the "FontAwesomeIcon" component, but that still doesn't work.
Can anyone help?
Well, this is one of the common pitfall you learn during your time with React. Rest assure, we have all fallen into this pit.
There are few AHA moments here.
1st Aha: React doesn't have a usual way to let you get element attribute in an event (an e in your example).
That being said, you can still access to the button element by e.target and use JavaScript to get attribute.
Solution #1 JavaScript getAttribute
editSchool(e) {
console.log("School Id");
console.log(e.target.getAttribute('id'));
}
e.target will be the HTML Element that you click, and we can use JavaScript way to get attribute. (Please Note that, Javascript way is not React way)
But there are another way and you'll see this way more often.
Solution #2 You can define a function directly in a render
<button id={school.id} onClick={e => this.editSchool(school.id)}>
Please be careful about this another pitfall,
2nd Aha: Bind onClick to function, not result of a function.
Don't do this
<button id={school.id} onClick={this.editSchool(scholl.id)}> // This is incorrect
The thing is onClick prop expect a function to call when someone click.
The first one we define a function e => this.editSchool(school.id) and bind onClick with the newly defined function.
While the second, we just bind onClick to a "result" of function this.editSchool(school.id), which is not a function.
How do I code this functionality in react-native?
eg. In Instagram when you go to your followers' page, you can view a whole list. You can tap on any of them and you will navigate to that user's specific profile.
I was wondering if it has something to do with React-Navigation like passing some unique id or code, but I am still unclear, please help me out.
P.S I am using cloud firestore from firebase as my database.
The way I would do this is as follows:
1) Create a FlatList:
<FlatList
data={//list of users}
renderItem={this.renderList}
keyExtractor={(item, index) => index.toString()}
/>
2) Every element in the FlatList is a custom component. Navigation props is also passed to the component along with the data. The handler function for renderItem is given below:
renderList = ({ item }) => (
<UserSummary data={item} navigation={this.props.navigation} />
);
3) UserSummary is in fact a Touchable element (say Touchable Opacity) and the onPress event handler for that is given below:
onPress={() =>
props.navigation.navigate("UserDetailsScreen", {
userDetails: props.data
})
Note that I have also passed some data along with the navigation. Let's say, it's some userID that is unique. This information can be used in the UserDetailsScreen to render the details of the user.
Hope this will give you an idea.
you can refer this link. You can pass id as parameter as this.props.navigation.navigate('RouteName', { /* params go here */ }) .
I have a table of user I am displaying to a user. They click a row, and I want to navigate to a component to show the details.
<tbody>
{this.state.clients.map(client => (
<tr className="tableRow" onClick={() => this.handleSelection(client.id)}>
<td>{client.name}</td>
My Route is setup like this:
<Route path="/client/:clientId" component={Client} />
So in the row, I have an onClick event, which calls a function, passing the parameter selected. Here's the function:
handleSelection(clientId) {
this.props.history.push(`/client/${clientId}`);
}
Then, in the constructor of the target component, I am just logging the selected id, which will be passed to the api to load the data:
console.log('Loading clientId...', this.props.match.params.clientId);
But this seem wrong. I get the right ID and all, but .. am I doing this right? Is there a better/safer way to do what I am doing?
Another option would just be to use individual Link tags inside each TD:
<td><Link to={`/client/${client.id}`}>{client.name}</Link></td>
That would also be more accessible, since vision impaired users might have trouble triggering that onclick event.
If you're using react-router-dom it has a Link component
{this.state.clients.map(client => (
<Link to={`/client/${clientId}`} >
<tr className="tableRow">
<td>{client.name}</td>
</Link>
It's better to use a link rather than an onClick on on a table row for accessibility.
If you're not using react-router-dom you can roll your own version from looking at the source - https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/modules/Link.js
By working in this way it'll behave correctly when people command click on the link to open it in a new tab.
For the routes you grab the params as you have, if you don't want the component to deal with match in the properties you can do something like this:
<Route path="/client/:clientId" children={({ match }) => (<Client {...match.params} />)} />
I have a component that shows a modal to pop up some content in my map. I have a pretty straight forward set up :
The JSX looks like this :
<Modal show={this.props.results.showPreviewModal} >
{myPreviewContent}
</Modal>
2 action-creators to open, close, and set the current item :
export function previewAsset(result) {
return {
currentResult: result,
type: actions.PREVIEW_ASSET
};
}
export function closePreviewModal() {
return {
type: actions.CLOSE_PREVIEW_MODAL
};
}
And their reducers :
case actions.PREVIEW_ASSET:
return state.set('currentPreview', action.currentResult).set('showPreviewModal', true);
case actions.CLOSE_PREVIEW_MODAL:
return state.set('showPreviewModal', false);
Now, this seems to work fine. However, the issue is that the component that has the modal inside of it is inside a map, as it is a singular search result (each result component has a some functionality so it is it's own component that is mapped over with results). The issue is that if I have 10 results, this modal opens 10 times when I click the button that fires the previewAsset action.
This makes sense, because the showPreviewModal is accessible by all components, but what I am wondering is if there is a way to make then unique for each component individually, so only the 1 modal opens, not all 10. Unsure how to approach this within react/redux, would very much appreciate any advice, thanks!
An approach I've used successfully is to pull the Modal component out of the loop (or map() in this case), and have a reducer for currentItem or something similar, which gets set when an item is selected (you could also use currentItemIndex, and then select the current item based on that in your connect() call).
In the parent component, you'd have the Modal as a child, and only display it if that currentItem is not null.
Here's a quick JSBin example to show you what I mean:
http://jsbin.com/fefoxoy/edit?html,js,console,output