Debounce mobx-react and props - mobx

I'm trying to debounce the method call: "chart.calculateChartData(props.answers)".
I tried:
- autorun
- reaction
- use-debounce from a react lib.
- setTimeout within calculateChartData
Each solution led to an update cycle or didn't work because MobX is not immutable.
Has someone a hint?
function QuantificationChart(props: QuantificationChartProps) {
const {t} = useTranslation();
const rootStore = useRootStore();
const chart = rootStore.formulaStore.getChart<Chart>(Chart.chartName);
const data = chart.calculateChartData(props.answers);
calculateChartData = (questionData: { [id: string]: number; } = {}) => {
let chartData = [];
for (let i = 0; i < this.numberOfYears + 1; ++i) {
let customData = {...questionData, "year" : i};
let chartEntry = {
cost: this.rootStore.formulaStore.calculateFormula(this.cost.formula, customData),
earn: this.rootStore.formulaStore.calculateFormula(this.earn.formula, customData),
sum: 0
};
chartEntry.sum = (chartEntry.earn - chartEntry.cost) + (chartData[i - 1]?.sum || 0);
chartData.push(chartEntry);
}
return chartData;
};
Hint: It's my first project with MobX

Found a solution. Seems to work:
Based on: https://mobx-react.js.org/recipes-effects
const [data, setData] = React.useState(chart.calculateChartData(props.answers));
React.useEffect(
() =>
autorun(() => {
setData(chart.calculateChartData(props.answers));
}, {delay: 1000}),
[],
);

Related

for loop only iterating twice with axios

const [Datalist,setDatalist] = useState([]);
useEffect(() => {
axios.get( 'http://0.0.0.0:8000/api/v1/questions/history/1')
.then(response => {
const questions = response.data;
const datalist = [];
for (let i = 0; i < questions.length - 1; i++) {
const data = new Object();
data.isExpanded = false;
data.question_id = questions[i].id;
data.question = questions[i].content;
data.type = questions[i].type;
data.commentType = questions[i].comment_type;
data.answer = [];
datalist.push(data);
}
setDatalist(datalist);
});
},[]);
I have three questions in my database currently. The for loop should be iterating through 0 to 2, however, it is only iterating twice.
And I'm also having problems putting the data into Datalist.
Anybody know where the issue is??
Thanks in advance!!
Change your for loop to this:
for (let i = 0; i < questions.length; i++)
Since you are iterating over each question you receive, you could use the map-method (if your environment supports ES6-Syntax - but since you're using react, it most likely dooes).
From the MDN Docs:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
With map, your code could look like this:
(Also note the removal of const data = new Object();. you can initialize an object and assign its properties/values at the same time)
const [Datalist,setDatalist] = useState([]);
useEffect(() => {
axios.get( 'http://0.0.0.0:8000/api/v1/questions/history/1')
.then(response => {
const questions = response.data;
const datalist = questions.map(question => {
return {
isExpanded: false;
question_id: question.id;
question: question.content;
type: question.type;
commentType: question.comment_type;
answer: [];
};
});
setDatalist(datalist);
});
},[]);

Testcafe: Is there a method to check for elements visible within the viewport? [duplicate]

I'm trying to implement a custom method to find out if the element is in the current view port
Below is the snippet of code that I've tried to implement but the outcome does not render the boolean result:
export const isElementInViewport = () => {
const getBoundValues = ClientFunction(() => document.querySelectorAll(".hero-getstart").item(0).getBoundingClientRect());
const windowHeight = ClientFunction(() => window.innerHeight);
const windowWidth = ClientFunction(() => window.innerWidth);
return getBoundValues.bottom > 0 && getBoundValues.right > 0 && getBoundValues.left < (windowWidth || document.documentElement.clientWidth) && getBoundValues.top < (windowHeight || document.documentElement.clientHeight);
};
The above code runs properly on the browser console, i.e when I try to store the getBoundValues in a variable A and try to run the return command, it prints the output as true or false depending on the visibility of the element in the viewport but in the script, It always gives a false:
Here's the method which triggers the above method:
export const verifyElementInView = () => {
const elementVisible = isElementInViewport();
console.log(elementVisible);
};
The output is always false.
Here's the snippet of output I receive upon trying to console.log(getBoundValues):
{ [Function: __$$clientFunction$$]
with: [Function],
[Symbol(functionBuilder)]:
ClientFunctionBuilder {
callsiteNames:
{ instantiation: 'ClientFunction',
execution: '__$$clientFunction$$' },
fn: [Function],
options: {},
compiledFnCode: '(function(){ return (function () {return document.querySelectorAll(".hero-getstart").item(0).getBoundingClientRect();});})();',
replicator:
{ transforms: [Array],
transformsMap: [Object],
serializer: [Object] } } }
What am I missing?
There's no need to create a client function for each client-side call. Instead, you can wrap the entire function into the ClientFunction call as follows:
const isElementInViewport = ClientFunction(() => {
const getBoundValues = document.querySelector("#developer-name").getBoundingClientRect();
const windowHeight = window.innerHeight;
const windowWidth = window.innerWidth;
return getBoundValues.bottom > 0 && getBoundValues.right > 0 && getBoundValues.left < (windowWidth || document.documentElement.clientWidth) && getBoundValues.top < (windowHeight || document.documentElement.clientHeight);
});
I recommend that you call your client function as follows (as described in the Executing Client Functions topic):
 
test('ClientFunctionCall', async t => {
const elementVisible = await isElementInViewport();
console.log(elementVisible)
});
 
The following example might also be useful: Complex DOM Queries

Expo-pixi Save stage children on App higher state and retrieve

I'm trying another solution to my problem:
The thing is: im rendering a Sketch component with a background image and sketching over it
onReady = async () => {
const { layoutWidth, layoutHeight, points } = this.state;
this.sketch.graphics = new PIXI.Graphics();
const linesStored = this.props.screenProps.getSketchLines();
if (this.sketch.stage) {
if (layoutWidth && layoutHeight) {
const background = await PIXI.Sprite.fromExpoAsync(this.props.image);
background.width = layoutWidth * scaleR;
background.height = layoutHeight * scaleR;
this.sketch.stage.addChild(background);
this.sketch.renderer._update();
}
if (linesStored) {
for(let i = 0; i < linesStored.length; i++) {
this.sketch.stage.addChild(linesStored[i])
this.sketch.renderer._update();
}
}
}
};
this lineStored variable is returning a data i've saved onChange:
onChangeAsync = async (param) => {
const { uri } = await this.sketch.takeSnapshotAsync();
this.setState({
image: { uri },
showSketch: false,
});
if (this.sketch.stage.children.length > 0) {
this.props.screenProps.storeSketchOnState(this.sketch.stage.children);
}
this.props.callBackOnChange({
image: uri,
changeAction: this.state.onChangeAction,
startSketch: this.startSketch,
undoSketch: this.undoSketch,
});
};
storeSketchOnState saves this.sketch.stage.children; so when i change screen and back to the screen my Sketch component in being rendered, i can retrieve the sketch.stage.children from App.js state and apply to Sketch component to persist the sketching i was doing before
i'm trying to apply the retrieved data like this
if (linesStored) {
for(let i = 0; i < linesStored.length; i++) {
this.sketch.stage.addChild(linesStored[i])
this.sketch.renderer._update();
}
}
```
but it is not working =(

App crash only if im not using debugger. Unable to overcome the situation. What should I do?

I'm facing a pretty ugly issue that I'm not able to overcome by myself, I just don't get it.
A short summary of my app purpose: You can find food around and make orders to restaurant owners.
I wrote a helper function that allows me to decide if the restaurant is open or closed based on its schedule “horarioSemanal” property.
This function take the restaurants queried from firestore as arguments and depending in some conditions it decide which value of the property “disponible” (available) it deserves.
The thing is that it works pretty well! So well that I published the changes through expo, and as expo has updates over-the-air and I have my app in both apptore and Google play it reached all my users…
None of my users were able to use my app until I removed the changes because I was unable to detect the issue. In my simulator it worked 100% but when the app was deployed crashed almost instantly.
Testing, testing, and testing I finally come to the issue but I still can't figure out what the hell should I do to overcome this situation.
The app while I use the js debugger it works perfectly! but when I turned off this new module I wrote doesn't work.
I recorded a video so you can see the same I'm watching on my screen:
https://www.youtube.com/watch?v=x9-t8-3XzKc
this is the action where im dispatching the action:
import { restaurantesHorarioValidado, validaDisponibilidadComidas } from '../../src/3-ResultadosComponents/Librerias/DisponibilidadHorario';
export const searchResultsInLocation = (ubicacion) => {
const db = firebase.firestore();
const docRef = db.collection('Restaurantes').where('abierto', '==', true).where(`zonaOperativa.zonaConsulta.${ubicacion}`, '==', true).get();
const restaurantesIDS = [];
return (dispatch) => {
const holder = [];
dispatch({
type: BUSQUEDA_DE_RESULTADOS,
});
docRef.then(querySnapshot => {
querySnapshot.forEach(doc => {
holder.push(doc.data());
restaurantesIDS.push(doc.data().id);
});
dispatch({
type: DESCARGA_RESTAURANTES_ABIERTOS,
restaurantes: restaurantesHorarioValidado(holder)
});
})
.then(() => {
const comidasRefs = [];
restaurantesIDS.forEach(restaurant => {
const ref = db.collection('Comidas').where('restaurantID', '==', `${restaurant}`).get();
comidasRefs.push(ref);
});
return Promise.all(comidasRefs).then(results => {
const comidas = [];
results.forEach(resto => {
resto.forEach(comida => comidas.push(comida.data()));
});
dispatch({
type: DESCARGA_COMIDAS,
comidas: validaDisponibilidadComidas(comidas, restaurantesHorarioValidado(holder))
});
})
.then(() => dispatch({
type: BUSQUEDA_DE_RESULTADOS,
}))
.catch(err => console.log('error; ', err));
});
};
};
here is how the reducer is handling the action:
case DESCARGA_COMIDAS:
return { ...state, comidas: action.comidas };
case DESCARGA_RESTAURANTES_ABIERTOS:
return { ...state, restaurantes: action.restaurantes };
this is the module I wrote and I'm using to create the object that the action creator send:
const diasDeSemana = ['Domingo', 'Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado'];
const today = new Date().getDay();
const hoyAbre = (horario) => {
if (horario) {
const JornadaHoy = horario.find(jornada => jornada.dia == diasDeSemana[today]);
return JornadaHoy;
}
return false;
};
export const isRestaurantAvalaible = (horario) => {
const Today = new Date();
if (hoyAbre(horario)) {
//Si el restaurant abre hoy
//Evalua si está abierto
const horarioApertura = () => {
const nuevoDia = new Date(`${Today.getFullYear()}, ${Today.getMonth() + 1} ${Today.getDate()} ${hoyAbre(horario).horario.apertura}:00`);
return nuevoDia;
};
const horarioCierre = () => {
//Si horario de cierre es hoy
const nuevoDia = new Date(`${Today.getFullYear()}, ${Today.getMonth() + 1} ${Today.getDate()} ${hoyAbre(horario).horario.cierre}:00`);
//Si el horario de cierre de hoy es pasado las 00:00
const cierraTomorrow = new Date(`${Today.getFullYear()}, ${Today.getMonth() + 1} ${Today.getDate() + 1} ${hoyAbre(horario).horario.cierre}:00`);
if (nuevoDia.getHours() <= 8) {
return cierraTomorrow;
}
return nuevoDia;
};
const isNowOpen = Today.getTime() >= horarioApertura().getTime();
const isNowClosed = Today.getTime() >= horarioCierre().getTime();
//Si está abierto
if (isNowOpen && !isNowClosed) {
return { estado: 'abierto' };
}
//Si abre mas rato
if (hoyAbre(horario) && (Today.getTime() < horarioApertura())) {
return { estado: 'abre pronto', horarioApertura: horarioApertura() };
}
//Si ya cerró
if (isNowOpen && isNowClosed) {
return { estado: 'ya cerro', horarioCierre: horarioCierre() };
}
}
//Si hoy no abre
if (!hoyAbre(horario)) {
return { estado: 'No abre hoy' };
}
};
export const restaurantesHorarioValidado = (restaurantes) => {
const restaurantesModificados = restaurantes.map(restaurant => {
return { ...restaurant, disponible: isRestaurantAvalaible(restaurant.horarioSemanal) };
});
const restaurantesAbiertos = restaurantesModificados.filter(restaurant => restaurant.disponible.estado == 'abierto');
const restaurantesProximosAbrir = restaurantesModificados.filter(restaurant => restaurant.disponible.estado == 'abre pronto');
const restaurantesCerrados = restaurantesModificados.filter(restaurant => restaurant.disponible.estado == ('ya cerro' || 'No abre hoy'));
return [...restaurantesAbiertos, ...restaurantesProximosAbrir, ...restaurantesCerrados];
};
export const validaDisponibilidadComidas = (comidas, restaurantes) => {
//Se le agrega la propiedad "disponible" del restaurant dueño
const comidasModificadas = comidas.map(comida => {
const Owner = restaurantes.find(restaurant => restaurant.id == comida.restaurantID);
return { ...comida, disponible: Owner.disponible };
});
const comidasDisponibles = comidasModificadas.filter(comida => comida.disponible.estado == 'abierto');
const comidasProximosAbrir = comidasModificadas.filter(comida => comida.disponible.estado == 'abre pronto');
const comidasNoDisponibles = comidasModificadas.filter(comida => comida.disponible.estado == ('ya cerro' || 'No abre hoy'));
return [...comidasDisponibles, ...comidasProximosAbrir, ...comidasNoDisponibles];
};
this is the error I get once I turned off the js debugger:
[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'restaurant.disponible.estado')]
Stack trace:
src/3-ResultadosComponents/Librerias/DisponibilidadHorario.js:65:98 in <unknown>
src/3-ResultadosComponents/Librerias/DisponibilidadHorario.js:65:62 in restaurantesHorarioValidado
store/actions/2-ResultadosActions.js:55:50 in <unknown>
node_modules/promise/setimmediate/core.js:37:14 in tryCallOne
node_modules/promise/setimmediate/core.js:123:25 in <unknown>
...
As it suggest there is some error with promises I tried making those functions work as promises. The errors disappear but the I didn't get the object back...
The question is this How the hell may this work just when the debugger it's on and not when it's turned off?
what should I do to get my life back?

React-Native componentWillRecieveProps rendering issue

In my RN project, I want to achieve this.
// componentWillReceiveProps
componentWillReceiveProps = async (nextProps) => {
let { searchText, peopleTab } = this.props;
let params = {};
if (peopleTab !== nextProps.peopleTab) {
params.peopleTab = nextProps.peopleTab;
}
// here i want to pass nextProps.searchText without a condition with the params like this.
// params.searchText = nextProps.searchText
if (Object.keys(params).length > 0) {
await this.props.fetchUnfollowedPeople(params);
}
}
I want to send nextProps.searchText with params object, if there is a new value. Otherwise I want to send this.props.searchText with the params object.
The above code, if I uncomment
// params.searchText = nextProps.searchText
it gives the infinity loop. How can I achieve this?
Setting the let { searchText, peopleTab } = this.props; in componentWillReceiveProps causes the new value to be pasted
componentWillMount() {
this.searchText = this.props.searchText ;
this.peopleTab = this.props.peopleTab ;
}
componentWillReceiveProps = async (nextProps) => {
const params = [];
if (this.peopleTab !== nextProps.peopleTab) {
params['peopleTab'] = nextProps.peopleTab ;
}
if (Object.keys(params).length > 0) {
await this.props.fetchUnfollowedPeople(params);
}
}