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.
Related
I have a list of components that are added upon button click, so every button click adds one of the components. Each component has a button that can be clicked to delete the component from the list.
Each pair of text "New Item" and button is created as one component in the insertNewCollectorFields function. This function is called when the maroon button is clicked. Each component is added to a list of components "collectorsList" to be displayed. For each component, I use the current length of this collectorsList as the id and key.
This is my code:
import {useEffect, useState} from "react";
export default function Test(){
const [collectorsList, setCollectorsList] = useState([])
const insertNewCollectorFields = () => {
setCollectorsList(collectorsList.concat(
<div id={collectorsList.length} key={collectorsList.length}>
<p>New Item</p>
<button onClick={()=>deleteNewCollectorFields(collectorsList.length)}>Delete New Item</button>
</div>
))
}
const deleteNewCollectorFields = (id) => {
console.log(id)
setCollectorsList(collectorsList.filter((item) => item.id!==id))
}
return <div>
{collectorsList}
<button type={"button"} className={`btn col-auto maroonButton`} onClick={insertNewCollectorFields}>Add Another Collector</button>
</div>
}
I am able to add the components, and I can delete components that were added last without an issue. However, if I delete one of the components that was added first, any component that was added after it is deleted too, and I don't understand why.
This is an example of the issue:
Here I add three components:
Now I delete that third component, and no issue:
If I however delete the first component, all three components disappear, and this is the issue:
I created the list of components as a state. This is my first big project using React. What I know is that on creating a state, the value is updated and should be seen by all the components with the updated value? But apparently on debugging, I found that the "collectorsList" seen by every component in the deleteNewCollectorFields function is limited to the list that was present before creating that component. For example, if collectorsList contained 6 components, component number 3 only sees that there is component 1 and 2 in the collectorsList, and does not see that the collectorsList actually contains 6 components. So on deleting component number 3, the filter process in the delete function results in only component 1 and 2, and everything else disappears from the screen.
I don't understand why this happens and why the components are not able to see the updated list with all the components that were added to it. I also searched for other examples were such a delete function was created and it seems that my method should work, and I couldn't find any case were this problem was faced.
What am I doing wrong? Is there something I understood incorrectly about the use of states?
Your problem is that you are using id={collectorsList.length}, which is wrong, because the .length is changing every time you delete an item and this give wrong id to the deleteNewCollectorFields, just make unique id
I have state like this
const [username,setUsername] = useState("")
const [password,setPassword] = useState("")
const [page,setPage] = useState("")
there is only one text input in entire page
in page 1 with prev and next bottom buttons
enter user name
in page 2 with prev and next bottom buttons
enter password
but when I move from page1 to page 2 or vice verse text input field become empty.
I am just hiding textinput according to page value
If these states are part of your Page1, whenever you are switching to Page2 you are unmounting Page1 and lifetime of states is till the time Page1 is mounted. Next time you are opening Page1 that is complete new fresh Page1.
If you want states should be persisted even on unmounting of pages you can go with following approaches:
1- Lift the state up
keep the states to parent component and pass the values/setter functions to the page.
const Dashboard=()=>{
const [username,setUsername] = useState("")
const [password,setPassword] = useState("")
const [page,setPage] = useState("")
const [activePage,setActivePage] = useState(0);
return(<div>
{activePage===0?<Page1 username={username} setUserName={setUserName}/>:null}
{activePage===1?<Page2 password={password} setPassword={setPassword}/>:null}
<button onClick={()=>{setActivePage(value=>value-1)}}>PREV<div/>
<button onClick={()=>{setActivePage(value=>value+1)}}>NEXT<div/>
</div>)
}
This way you are not unmounting parent component so state will not be on page changing.
2- Use any central state management library (redux/mobx/context)
The state will NOT stay alive longer then your component (I mean, whenever you change current page, the previous page is destructed).
What you seem to be aiming for can be called "persistent" state, or Application-wide state.
Redux is one of such persistent state implementions:
https://redux.js.org/introduction/getting-started
I am creating a shopping page. I am keeping a JSON to store the product details. I have created the product as a component and using it in the shopping page. For each product I am keeping a drop down to select the quantity (0-5, default value is 0).
Whenever a drop down value change happens, I am making a call back to the parent which is the product page where I am updating the total count. I am using useState hook to update the total. The issue is that when I call the setState, the drop down is not showing the selected value, but the default one (My strong guess is that the drop downs are getting reset. When I remove the setState call, the drop downs work fine).
I am using react-dropdown for implementing drop down.
Parent Component:
const [total,setCartTotal] = useState(0)
const calculateTotalCartValue = (count) => {
setCartTotal(total+count)
}
// Adding the child Component
<Cartitem
parentCallback={calculateTotalCartValue}
/>
Child Component:
const calculateTotal = (event) => {
console.log(event) // This is properly printing the selected drop down details
parentCallback(2) // for testing I am passing value 2
}
// Drop down
<Dropdown
options={options} // I have a list of options
value={defaultOption}
onChange={calculateTotal}
/>
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 */ }) .
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>