it's possible to set timer on reducer state? React + Redux - javascript

it's possible to set a timer to clear some reducer state? i have a state to show message of "success", "error", "warning"
Example:
Reducer:
const statusState = {
status: {action: '', result: ''}
}
...
CASE fetchContent:
return {
...state,
contents: [...state.contents, action.data],
status: {
...state.status,
action: action.type,
result: action.result
}
}
Component:
render(){
cost { status } = this.props
if(status.action == "something" && status.result == "success"){
alert("success");
}
}
const mapStateToProps = store => ({
status: store.initialState.status
});
export default connect(mapStateToProps)(Component);
if i don't clear status.action and status.result the alert will show all the time, it's possible to set a timer to clear it?

Create a clear action which clears status.action and status.result. Create a javscript timeout function that calls clear action after timeout. Something like below:
clearStatus = ()=>{
setTimeout(
function() {
//create a action that clears status and result
},3000
);
}
render(){
cost { status } = this.props
if(status.action == "something" && status.result == "success"){
//showMessage
clearStatus();
}
}

Related

Vue, Vuex & remote storage

Well a have some value in remote storage (lets say x) and b-form-checkbox that should control this value. I want to inform user if value actually changed on storage and time when it happens.
So basically I want:
When user check/uncheck b-form-checkbox I want to change state of b-form-checkbox, send async request to the remote storage and show some b-spinner to indicate that state isn't actually changed yet.
When I receive answer from remote storage:
if change was successful just hide b-spinner.
if change was not successful (timeouted, error on server, etc) I want to change b-form-checkbox state back (since value actually doesn't changed on storage) and hide b-spinner
What is the silliest way to do int using Vue + Vuex?
Currently I'm doing it this way:
xChanger.vue:
<template>
<b-form-checkbox v-model="xComp" switch>
{{xComp ? 'On' : 'Off'}}
<b-spinner v-if="!xSynced"/>
</b-form-checkbox>
</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex';
export default {
name: 'XChanger',
computed: {
...mapState(['x']),
...mapGetters(['xSynced']),
xComp: {
get() { return x.local },
set(value) {
if (value != this.x.local) {
this.setX(value)
}
},
},
},
methods: {
...mapActions(['setX']),
},
}
</script>
main.js
import Vuex from 'vuex'
import Axios from 'axios'
const store = new Vuex.Store({
state: {
x: {
remote: null,
local: null
},
getters: {
xSynced(state) {
state.x.local === state.x.remote
}
},
actions: {
async setX(store, value) {
store.state.x.local = value
try {
let response = await Axios.post('http://blah.blah/setX', {x: value});
if (response.status == 200) {
store.state.x.remote = value
}
} catch (error) {
store.state.x.local = !value
}
}
},
mutations: {
setX(state, value) {
state.x.local = value
state.x.remote = value
}
}
},
})
But it is too verbose for just one value to be controlled (especially computed property xComp). I'm sure that such a simple template should be already solved and has more simple way to implement.
Here is an example:
<template>
<b-form-checkbox v-model="x.local" switch>
{{x.local ? 'On' : 'Off'}}
<b-spinner v-if="saving"/>
</b-form-checkbox>
</template>
<script>
export default
{
name: 'XChanger',
data: () => ({
x:
{
local: false,
remote: false,
},
saving: false,
}),
watch:
{
'x.local'(newValue, oldValue)
{
if (newValue !== oldValue && newValue !== this.x.remote)
{
this.updateRemote(newValue);
}
}
}
methods:
{
async updateRemote(value)
{
try
{
this.saving = true;
const response = await Axios.post('http://blah.blah/setX', {x: value});
if (response.status == 200)
{
this.x.remote = value;
}
else
{
this.x.local = this.x.remote;
}
}
catch (error)
{
this.x.local = this.x.remote;
}
this.saving = false;
}
},
}
</script>

How to sum the value only once in react redux

I would like to know in my scenario: After receiving props, the function gets called in the compoentdidupdate method, in which am summing up the amount if id is same, But it keeps on adding the values multiple times on load. how to resolve this.
class Data extends React.PureComponent{
constructor(props){
super(props);
this.state={
total: "";
}
}
componentDidMount() {
this.callFetch();
}
callFetch(){
this.props.dispatch(getData("all"));
this.props.dispatch(newData("new"));
}
componentDidUpdate(){
const { alldata, newdata } = this.props.query;
const obj =[...alldata, ...newdata];
const result=[];
if(obj.length > 0) {
obj.forEach(function (o) {
var existing = result.filter(function (i) { return i.id=== o.id})[0];
if (!existing)
result.push(o);
else
existing.amount+= o.amount;
});
this.setState({total: result})
}
}
render(){
return(
this.state.total.length > 0 ?
this.state.total.map(e=>{
<div>price:{e.amount}</div>
}) : ""
)
}
props am receiving is below, but in output am receiving 1200, and keeps on increasing,
alldata= [{
id: 1,
amount: 200
}, {
id: 2,
amount: 400
}]
newdata= [{
id: "1",
amount: 400
}]
expected output:
price: 600
price: 400
Hey #miyavv Have a look at the below piece of code. Comparing prevProps and current props should help. It is general technique used in reactjs to solve non-needed runs in componentDidUpdate.
class Data extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
total: ""
};
}
componentDidMount() {
this.callFetch();
}
callFetch() {
this.props.dispatch(getData("all"));
this.props.dispatch(newData("new"));
}
componentDidUpdate(prevProps) {
const { alldata, newdata } = this.props.query;
const obj = [...alldata, ...newdata];
const result = [];
// new Line added
const { alldata: prevAllData, newdata: prevNewData } = prevProps.query;
if (prevAllData !== alldata || prevNewData !== newdata) {
if (obj.length > 0) {
obj.forEach(function(o) {
var existing = result.filter(function(i) {
return i.id === o.id;
})[0];
if (!existing) result.push(o);
else existing.amount += o.amount;
});
this.setState({ total: result });
}
}
}
render() {
return this.state.total.length > 0
? this.state.total.map(e => {
<div>price:{e.amount}</div>;
})
: "";
}
}
Let me know if it helps !!. Thanks
That’s because you are dispatching two actions which will result to call componentDidUpdate multiple times. And in your componentDidUpdate method there’s no conditioning telling that your data is already fetched.
You could call only one action that will further dispatch two actions you are dispatching in callFetch method. You could also keep a flag which will tell whether the data is yet fetched or not.
If you are using redux-thunk, than it can be easily achieved. You can define one action which will be dispatched in callFetch method. And in your newly defined action you can dispatch your mentioned two actions.

How to clear fields after callback from axios?

I have modal component with form. I want to inform fields of this form that form data was successfully sent to database and clear its fields.
Component code:
//ItemModal.js
addItem(e) {
e.preventDefault();
const item = {
id: this.props.itemsStore.length + 1,
image: this.fileInput.files[0] || 'http://via.placeholder.com/350x150',
tags: this.tagInput.value,
place: this.placeInput.value,
details: this.detailsInput.value
}
console.log('addded', item);
this.props.onAddItem(item);
this.fileInput.value = '';
this.tagInput.value = '';
this.placeInput.value = '';
this.detailsInput.value = '';
this.setState({
filled: {
...this.state.filled,
place: false,
tags: false
},
loadingText: 'Loading...'
});
}
...
render() {
return (
<div className="text-center" >
<div className={"text-center form-notification " + ((this.state.loadingText) ? 'form-notification__active' : '' )}>
{(this.state.loadingText) ? ((this.props.loadingState === true) ? 'Item added' : this.state.loadingText) : '' }
</div>
)
}
action.js
export function onAddItem(item) {
axios.post('http://localhost:3001/api/items/', item )
.then(res => {
dispatch({type:"ADD_ITEM", item});
dispatch({type:"ITEM_LOADED", status: true});
})
}
helper.js
else if (action.type === 'ITEM_LOADED') {
const status = action.status;
return {
...state,
isItemLoaded: status
}
}
Currently I have few issues with my code:
1. field are clearing right after click, but they should clear after changing state of loadingState. I tried to check it in separate function on in componentWillReceiveProps whether state is changed and it worked, but I faces another problem, that after closing this modal there were errors, that such fields doesn't exist.
2. loadingText should become '' (empty) after few seconds. Tried same approach with separate function and componentWillReceiveProps as at first issue.
In constructor keep a copy of your initial state in a const as follows:
const stateCopy = Object.create(this.state);
When your ajax request completes, in the sucess callback you can reset the state with this copy as follows:
this.setStae({
...stateCopy
});
One of the few ways to achieve this is to use async await which will resolve the promises and then return the value after that you can clear the values
1st approach using the async await
Here is the example
handleSubmit = async event => {
event.preventDefault();
// Promise is resolved and value is inside of the response const.
const response = await API.delete(`users/${this.state.id}`);
//dispatch your reducers
};
Now in your react component call it
PostData() {
const res = await handleSubmit();
//empty your model and values
}
Second approach is to use the timer to check the value is changed or not
for this we need one variable add this to the service
let timerFinished=false;
one function to check it is changed or not
CheckTimers = () => {
setTimeout(() => {
if (timerFinished) {
//empty your modal and clear the values
} else {
this.CheckTimers();
}
}, 200);
}
on your add item change this variable value
export function onAddItem(item) {
axios.post('http://localhost:3001/api/items/', item)
.then(res => {
timerFinished = true;
dispatch({
type: "ADD_ITEM",
item
});
dispatch({
type: "ITEM_LOADED",
status: true
});
})
}
and here is how we need to call it.
PostData = (items) => {
timerFinished = false;
onAddItem(items);
this.CheckTimers();
}
If you check this what we done is continuously checking the variable change and emptied only once its done.
One thing you need to handle is to when axios failed to post the data you need to change the variable value to something and handle it, you can do it using the different values 'error','failed','success' to the timerFinished variable.

How to make this setState function non recursive

I am learning react and is in very early stages. I was trying to add a object to an array from another component to a different component. I was able to achieve this using props but now when I try to set it in this.state setState calls the render function again thus triggering this function again. I was able to solve this problem using a button but I don't want to do it this way. Is there some better way to do this?
getData() {
if (this.props.data.employeeData !== undefined) {
if (this.props.isNewEmployee === "true") {
this.setState({
isNewEmployee: "true",
});
setTimeout(() => {
if (this.state.isNewEmployee === "true") {
console.log(this.props.data.employeeData.firstName);
var joined = this.state.EmployeesList.concat(this.props.data.employeeData);
this.setState({
EmployeesList: joined,
isNewEmployee: "false",
})
}
else {
console.log("Don't know what's happening anymore");
}
}, 100);
}
else {
console.log("No new employee added");
}
}
else {
console.log("Something went wrong");
}
}
render() {
return (
<div>
{this.getData()}
{this.renderTable()}
{this.renderFloatingActionButton()}
</div>
)
}
If the intent of the props is to add the new data to the table I would be doing something in these lines.
componentWillReceiveProps(nextProps) {
if (this.props.data.employeeData && nextProps.isNewEmployee !== this.props.isNewEmployee) {
console.log(this.props.data.employeeData.firstName);
var joined = this.state.EmployeesList.concat(this.props.data.employeeData);
this.setState({
EmployeesList: joined,
isNewEmployee: "false",
});
} else {
console.log("No new employee added");
}
}
render() {
return (
<div>
{this.renderTable()}
{this.renderFloatingActionButton()}
</div>
)
}

Vuex how to pass state/getter in data prop

I retrieved my data from database using axios under my vuex
const state = {
giveaways: null
}
const actions = {
getGiveAways : ({commit}) =>{
axios({
url : '/prod/api/thresholds_settings',
method: 'post',
data : {
},
config: 'JOSN'
})
.then(response=>{
if(response.status == 200){
//console.log(response.data.total_giveaways);
commit('SET_GIVEAWAYS', response.data.total_giveaways)
}
})
.catch(error=>{
if(error.response){
console.log('something happened')
}
});
}
}
const mutations = {
SET_GIVEAWAYS : (state, obj)=>{
state.giveaways = obj
}
}
const getters = {
doneGiveAways(state){
return state.giveaways
}
}
In my Dashboard.vue I have
import {mapState,mapGetters} from 'vuex'
export default{
data: () => ({
cards: [],
giveaways: ''
}),
computed:{
...mapState({
Giveaway: state => state.Threshold.giveaways
}),
doneGiveAways(){
return this.$store.getters.doneGiveAways
}
},
ready(){
//giveaways: this.Giveaways
//console.log(this.Giveaways);
},
created(){
const self = this
this.cards[0].result_val = 2
this.cards[2].result_val = 2;
},
mounted(){
this.$store.dispatch('getGiveAways');
console.log(this.giveaways);
}
}
My problem is I need to pass the value from the mapState Giveaway to my returning data giveaways: '' so when page fires I can get the response value using this.giveaways. If I just call {{ Giveaway }} in my html it shows the value. But I need to make something like this.giveaways = this.$store.state.Thresholds.giveaways
I would use Stephan-v's recommendation and delete the local copy of giveaways. But I don't know what your specific reason is for declaring an extra copy of giveaways, so here is a solution that will work:
In your Dashboard.vue add:
export default {
...
watch: {
Giveaway(value) {
this.giveaways = value
}
},
...
}
Just delete the giveaways property from your data Object and rename the computed doneGiveAways to giveaways and you are done.
There is no need for a local component giveaway data property in this scenario.

Categories

Resources