I have problem with pager click to re-render list users. Please check on my logic below
Firstly, I list all users by calling an action is ListUsersAction like this:
const ListUsers = props => {
useEffect(() => {
var resPerPage = configList.users.resPerPage;
props.ListUsersAction(resPerPage, 1);
},[]);
.....
.....
}
I used a reducer listUsersReducer to store users. I call it like that:
if (props.listUsersReducer.thanhvien.length > 0) {
const users = props.listUsersReducer.thanhvien;
//Then render all user here.
users.map((user)=>....);
//I make a pagination to change users list by click on each page.
<Pagination datasend={datasend} />
}
I has no problem from first load. And problem occur when I click 6-7 times on pagination to call LoadUsersAction. It start slowly and make page lag.
Action called every time click page change.
I do not know anything I made wrong. Can you help me to check it. Thank you so much.
Problem is solved. It is not related to redux. It is store.subscribe render multiple times. Just add it in useEffect and it is solved.
Related
This is a difficult one to explain so I will do my best!
My Goal
I have been learning React and decided to try build a Todo List App from scratch. I wanted to implement a "push notification" system, which when you say mark a todo as complete it will pop up in the bottom left corner saying for example "walk the dog has been updated". Then after a few seconds or so it will be removed from the UI.
Fairly simple Goal, and for the most part I have got it working... BUT... if you quickly mark a few todos as complete they will get removed from the UI and then get re-rendered back in!
I have tried as many different ways of removing items from state as I can think of and even changing where the component is pulled in etc.
This is probably a noobie question, but I am still learning!
Here is a link to a code sandbox, best way I could think of to show where I am at:
Alert Component State/Parent
https://codesandbox.io/s/runtime-night-h4czf?file=/src/components/layout/PageContainer.js
Alert Component
https://codesandbox.io/s/runtime-night-h4czf?file=/src/components/parts/Alert.js
Any help much appreciated!
When you call a set function to update state, it will update from the last rendered value. If you want it to update from the last set value, you need to pass the update function instead of just the new values.
For instance, you can change your setTodos in your markComplete function to something like this.
setTodos(todos => todos.map((todo) => {
if (id === todo.id) {
todo = {
...todo,
complete: !todo.complete,
};
}
return todo;
}));
https://codesandbox.io/s/jovial-yalow-yd0jz
If asynchronous events are happening, the value in the scope of the executed event handler might be out of date.
When updating lists of values, use the updating method which receives the previous state, for example
setAlerts(previousAlerts => {
const newAlerts = (build new alerts from prev alerts);
return newAlerts;
});
instead of directly using the alerts you got from useState.
In the PageContainer.js, modify this function
const removeAlert = (id) => {
setAlerts(alerts.filter((alert) => alert.id !== id));
};
to this
const removeAlert = (id) => {
setAlerts(prev => prev.filter((alert) => alert.id !== id));
};
This will also fix the issue when unchecking completed todos at high speed
Please, See this - https://codesandbox.io/s/morning-grass-z8qrq
https://codesandbox.io/s/blue-flower-wl92u
** the second click, third, fourth, fifth click - menuOpen is true, then again click false - behaves as expected**
let [menuOpen, setMenuOpen] = useState(false);
<div
onClick={() => {
// setMenuOpen(true);
setMenuOpen(!menuOpen); // I's not updated in the First time.
console.log(menuOpen); // First time: false // not updating
>
.......// some code
</div>
Please give me, some answers. I have been trying to solve this problem for Two days. I just can't solve it.
Try this:
export default function App() {
const [menuOpen, setMenuOpen] = useState(false);
return (
<>
<button onClick={() => setMenuOpen(!menuOpen)}>Click</button>
Is menu Open: { menuOpen ? "True": "False"}
</>
);
}
Example demo can be found here.
useState create queues for React core to update the state object of a React component. So the process to update React state is asynchronous for performance reasons. That's why changes don't feel immediate.
Give this a try
setMenuOpen(prevMenuOpenState => !prevMenuOpenState);
or
<div
onClick={() => setMenuOpen(!menuOpen)}
>
I had even this problem in my code. My scenario is as follows:
Its hotel detail page. There is horizontal tab menu of room types. If a hotel has more than 3 types of room, then there is show room button. I am using React Functional components in through the code. hotel detail basic page and room section page are different components created. values are passed to room section components through props.
My problem: When I click to room type further 3rd type, then show room value in function (setSelectedTab()) room component doesn't set at an instant. And hence as function moves further, it doesn't set document.getElementById(id) since show room had not been set. As function (setSelectedTab()) completes in first click it sets the show room to true, but selected tab doesn't set. I had to click 2nd time to set the tab.
solution:
After a long try and error, I settle down to the following:
I declare the function as async and made await the setshowRoom() value.
This solved my complete problem.
async function setSelectedTab(e, data) {
firstScroll += 1;
data >= 2 && await setMenuOpen(true);
if (data >= 0) {
.................
const id = e.href;
const anchor = document.getElementById(id);
..............
..............
}
}
and in room component: showRoom, setshowRoom in useState and calling the setSelectedTab() using props. This solves problem of single click
Drawback: I found delay of 1 second to set this tab.
If anyone have better solution than this without making async await, then please post here.
Thanks.
The Answer is just refactoring the code into class Component without using hooks useState. Using state and setState to update. The Problem will solve.
But If I use useState hooks the problem remains the same Whatever I do with the code.
I'm making some updates to one of my VueJS apps, and there are a few different ways I could go about it. I wanted to know what the best practice was in terms of performance, or if there isn't much of a difference at all.
Essentially I have a couple of different pages, each of these pages present results in a table. I'm using Boostrap to manage the tables. What I want to do is have a button at the far end of the table that opens a modal where you can see detailed results for that specific line entry in the table.
Now because there are tables on different pages and I want the same behaviour, I want to have the modal / button in their own component, that way I can just copy-paste the component from one page to the next and have the exact same behaviour.
My question is this, is there a difference between :
Having the modal on the page itself, and having all the logic in the page itself
Having a component containing the modal and the logic, and repeating that component 1000s of times in the different tables
Is there any performance difference between having the modal repeated 1000 times in the table versus having only one modal in the page? My understanding is that the modal wouldn't be loaded until you click the button anyway, so would it have an impact on performance?
The way that I would approach this would be to use a Vuex store. When a user clicks the button just go set the data in the store, and then have your modal component import this same store and get the data it needs. That way whenever you want to use the modal anywhere in the application you can as long as the data it needs has been set in the store, and you'll (hopefully) have a nice design to just do something like this.$dialogs.popMyCoolModal(data)
Something like this:
...mapActions({
setButtonData: actionTypes.SET_BUTTON_DATA
})
Then on click of the button just call this mutation, pass it the payload that it needs. I'm just calling it the horrible name of buttonData since I'm not sure what your data actually looks like.
In your store:
export const actionTypes= Object.freeze({
SET_BUTTON_DATA: `setButtonData`
});
export const actions: ActionTree<State, State> = {
async setButtonData({commit, state}, buttonData: ButtonData) {
const data = await someApi.getData(buttonData);
commit('setButtonDataState', data);
// Pop your modal here... how you pop it entirely depends upon your modal implementation
}
};
export const mutations: MutationTree<State> = {
setButtonDataState(state: State, data: SomeData) {
state.data = data;
}
}
Then in your store after you set the data you can simply pop the modal component in the action, the modal component will take care of the rest.
I created a component in react that displays table.
The process is executed in this way:
Enter api url and hit Load Button -->
Select the functionalities you want with the table (like Sortable columns, resizable columns, search implementation, responsiveness, row reorder, download data, multiselect columns and draggable columns) -->
Click Load Table button to load table.
The entire process is happening but if i refresh the page, it starts from all over again. I have to re enter the api, select functionalities and load table. Is there any way that i can store the api and functionalities so that next time if i load the page it takes previous configuration.
Also if i call the component twice, at two different places in the same webpage. The configuration should be different for the other component. How can i implement that?
To persist the state of your components in React, you could use SessionStorage. This is a built in storage which you can use to store JSON objects in the browser of the user. See https://developer.mozilla.org/nl/docs/Web/API/Window/sessionStorage for more information.
You can start with something quite simple, using LocalStorage
// Read
let yourConfigObject = JSON.parse(window.localStorage.getItem('config'));
// Write
window.localStorage.setItem('config', JSON.stringify(yourConfigObject));
Your process will become :
1 - Enter API url and hit load button.
2 - Check existing config using LocalStorage.getItem.
If there is no such config, let the user select the options he wants.
3 - Persist the options using LocalStorage.setItem, then load all the data
.
As commented before:
You need to persist values. You can look at SessionStorage or any HTML5 storage. For your reference: Keep input value after refresh page
Idea:
Create a component which takes 2 function callbacks
initState: This will initialize the state and initial behavior. This can be done outside as well. Its on your preference.
clickCallback or actionDispatcher: This will be called on a specific event and will be responsible for setting value to state.
Basic idea is to keep the component as dumb as possible. They will be responsible only for user interactions. All data manipulation/ loading will be done in reducer or any other function.
Following is a simplified example:
const { useState, useEffect } = React;
const DummyComp = (props) => {
const [ loaded, setLoaded ] = useState(false);
const [ msg, setMsg ] = useState('');
useEffect(() => {
loaded && setMsg('Data has been loaded. Calling callback');
props.onLoadHandler && props.onLoadHandler();
}, [ loaded ])
return (
<div>
<p> { msg } </p>
<button disabled={loaded} onClick={() => setLoaded(true)}>Load Data</button>
</div>
)
}
const MyApp = () => {
const handler1 = () => console.log('Dispatching event 1');
const handler2 = () => console.log('Dispatching event 2');
return (
<div>
<DummyComp onLoadHandler={() => handler1}/>
<DummyComp onLoadHandler={() => handler2}/>
</div>
)
}
ReactDOM.render(<MyApp/>, document.querySelector('.content'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>
<div class='content'></div>
When Promise.all resolves and the new activity is saved, the user should be routed to /activities to view their newly created activity. Everything works as expected, however I currently need to refresh /activities page (once) after being routed in order to view the new activity in the table.
const handleSaveActivity = e => {
e.preventDefault();
Promise.all([
addActivity(),
saveActivity()
]).then(() => {
props.history.push('/activities');
})
};
I'm not sure how to re-render the page automatically after pushing a new history state, so the user does not need to manually refresh the page to see the new state. Happy to provide more code snippets if I left out something critical.
Hi i must be a little late to answer this, but this issue can be due to the wrong use of useEffect, if you have lets say a todo list and you wanna fetch data with axios for example, it would look like this:
useEffect(()=>{
axios.get(`${YOUR_URL}/todos`)
.then((res)=>{
setTodos(todos=res.data)
})
},[])
now as you can see we have initial value of an empty array, so this is acting as a ComponentDidMount, what you might want is to re render the component after it gets a new value, so you want to have a ComponentDidUpdate effect, so you would just not initialize the value as an empty array, therefore it would look like this:
useEffect(()=>{
axios.get(`${YOUR_URL}/todos`)
.then((res)=>{
setTodos(todos=res.data)
})
})
Hope this helps someone, couse i landed here due to the same issue and came to solve it this way.
just to run this.setState({whateverKey:whateverValue})?
In your activities page (call it Activities component) you should call API to get the updated data every time browser hit this component URL.
With class based style, you should do it in componentDidMount life cycle hook
class Activities extends Component {
// ...
componentDidMount() { loadActivities() }
// ...
}
With function based style, you should do it in useEffect hook
import React, { useEffect } from 'react'
const Activities = () => {
useEffect(() => { loadActivities() });
}
https://github.com/supasate/connected-react-router Please use this package, it solves the problem.
This issue I've faced a few minutes ago...however I finally found the solution by manually using the vanilla javascript. => for refreshing the page you can use
=> window.location.reload(false); after using the push property.