Why component doesn't rerender? - reactjs

const [dammy, setDammy] = useState({
name: "any",
status: {
"1.0.1": "Successfylly installed",
"1.0.2": "Successfylly installed",
"1.0.3": "Successfylly installed",
"1.0.4": "Successfylly installed",
"1.0.6": "Installing",
"1.0.7": "In Queue",
"1.0.8": "In Queue",
"1.1.1": null,
"1.1.2": null,
"1.1.36": null,
"1.1.4": null,
"1.1.5": null,
"1.1.6": null,
},
available: ["1.1.1", "1.1.2", "1.1.36", "1.1.4", "1.1.5", "1.1.6"],
queue: ["1.0.7", "1.0.8"],
date: new Date()
})
function addingToQueue(e: MouseEvent < HTMLDivElement > , i: number) {
setDammy(prev => {
let val = prev["available"].splice(i, 1)
prev["queue"].push(val[0])
console.log(prev) // <-- I could see changes has been applied
return prev
})
}
component doesn't rerender even tho I could see that in setDummy console show's the right object data. But after completing function pre-render doesn't happen and on a screen I see no changes.

Because you're not actually returning a new array in your callback to setDammy-- you're merely mutating the previous one and returning it; when React does its comparison, it will see that the returned object is still the same reference. Instead, spread into a new array and alter that:
setDammy(prev => {
const newArr = [...prev];
let val = newArr["available"].splice(i, 1)
newArr["queue"].push(val[0])
console.log(newArr) // <-- I could see changes has been applied
return newArr
})

Related

why callback is a number not function in React Scheduler?

I suspect the Fiber has a bug
I use some Hooks in React-Native of 0.59. My react version is 16.8.3.
flushedNode.next = flushedNode.previous = null;
// Now it's safe to call the callback.
var callback = flushedNode.callback;
var expirationTime = flushedNode.expirationTime;
var priorityLevel = flushedNode.priorityLevel;
var previousPriorityLevel = currentPriorityLevel;
var previousExpirationTime = currentExpirationTime;
currentPriorityLevel = priorityLevel;
currentExpirationTime = expirationTime;
var continuationCallback;
try {
[ this is the mistake ] continuationCallback = callback();
} finally {
currentPriorityLevel = previousPriorityLevel;
currentExpirationTime = previousExpirationTime;
}
Now, let me show the bug.
flushedNode is {
callback: 3,
expirationTime: 220678.60500000097,
next: null,
previous: null,
priorityLevel: 3,
__proto__: Object
}
Callback should be a function but it is a number showed 3,so the app is crashed, why?
In the latest unstable version, https://github.com/facebook/react/blob/master/packages/scheduler/src/Scheduler.js#L320
function unstable_scheduleCallback(priorityLevel, callback, options) {
var newTask = {
id: taskIdCounter++,
callback,
...
}
return newTask
}
so yes, it should be the callback you used to schedule. And this callback is later used to execute the work in workLoop, https://github.com/facebook/react/blob/master/packages/scheduler/src/Scheduler.js#L185

How to write array with deleted image id?

When i remove images from news i catch id, and id come to along.
How to write in array all this lonlies id ?
How to create streamIds array with streamId ?
this.state = {
mainImage: null,
mainImageUrl: "",
crop: {
aspect: 2 / 1
},
pixelCrop: null,
cropped: false,
loaded: false,
streamIds: []
};
removeImage(imageKey, streamId) {
const {singleNews} = this.props;
let streamIds = this.state.streamIds;
console.log(streamId);
singleNews.secondaryImages.splice(imageKey, 1);
if (!singleNews.secondaryImages.length) {
singleNews.secondaryImages = null;
delete singleNews.secondaryImages;
this.props.updateSingleNews(null, singleNews);
} else {
streamIds.push(streamId);
singleNews.secondaryImages.map(image => {
const index = singleNews.secondaryImages.indexOf(image);
if (index > -1) {
singleNews.secondaryImages.slice(index, 1);
FilesApi.getDocument(image.streamId).then(resp => {
singleNews.secondaryImages[index] = new File([resp], image.name, {lastModified: Date.now()});
});
}
});
this.props.updateSingleNews('streamIds', streamIds);
}
}
this is your method
If not in this func where i need to place
if you want to keep the array of ids in the same component, use
let streamIds = [];
at the top of your react component and do
removeImage (imageKey, streamId) {
console.log(streamId);
streamIds.push(streamId); // insert the item to array
}
in your removeImage method
if you want to keep the removed ids in the application state, then the concept is the same, but it need to be done on the state management tool you are using (like redux, mobx etc)

Running a forEach() on an Array of Objects After Retrieving with findOne() in Mongo Back-end

I am using findOne() to retrieve a document like this:
let staffToUpdate = await Staff.findOne({
_id: request.parameters.id
}).exec();
let historyArray = await crewToUpdate.history;
console.log("historyArray: ", await historyArray);
console.log(Array.isArray(historyArray)); // returns true
The data looks like this:
history: [
{
status: "active",
startDate: <Date>,
endDate: <Date>,
completed: false
},
{
status: "training",
startDate: <Date>,
endDate: <Date>,
completed: true
}
]
When I do the above I get an array of objects printed out, as well as a return of "true" on the check to see if "historyArray" is indeed an array.
So now that I have this array, I'd like to run a transformation on the objects found within it, like so:
let updatedHistoryArray = historyArray.then(
updatedHistoryArray.forEach(history => {
history.completed = true;
history.endDate = new Date();
})
);
However, this is the part that's not working. When I try this I get this error:
Reason: ReferenceError: historyArray is not defined
What am I missing here?
UPDATE: After a suggestion from a commenter below, I tried this:
let staffToUpdate = await Staff.findOne({
_id: request.parameters.id
}).exec();
let staffObject = staffToUpdate.toObject();
let historyArray = await staffObject.history;
console.log(await historyArray); // prints the array
console.log(Array.isArray(historyArray)); // returns true
historyArray.forEach(history => { // this is where the error occurs
history.completed = true;
history.endDate = new Date();
});
With this last block of code I get this error:
Reason: ReferenceError: historyArray is not defined
historyArray is not a Promise and you can not run then on it.
When this code runs
let staffToUpdate = await Staff.findOne({
_id: request.parameters.id
}).exec();
it waits until query is executed and assigns the actual result (mongoose Document), not a promise and assigns it to staffToUpdate. You need to run toObject() on mongoose Document to get plain object without the wrapper:
const unwrappedStaffToUpdate = staffToUpdate.toObject();
After that you don't need to use await on crewToUpdate.history because it is not a Promise and it is synchronious. That is why you can not run then on historyArray because it is a normal Array and not a Promise.
Try this code:
unwrappedStaffToUpdate.historyArray.forEach(history => {
history.completed = true;
history.endDate = new Date();
});
Or if you do not want to mutate your Array use map instead of forEach:
const updatedHistoryArray = unwrappedStaffToUpdate.historyArray.map(history => ({
...history
completed: true;
endDate: new Date()
})
);

console.log prints changed state before changing

I'm trying to rearrange div's with React/Redux via Drag&Drop and there is a strange behavoir that i cant explain. I have the following reducer (reduced version for readability)
There are 5 "console.log" around the middle of the code. When i log state or structs the chrome console will print the already rearrange version. why?
export default function reducer(
state={
structures: [],
elementUniqueCounter: 0,
hoveredElement: null,
DnD: {
dragContent: null,
dragOverContent: null,
dragContentTop: true,
dragStructure: null,
dragOverStructure: null,
dragStructureTop: true,
content: null,
mousepositon: {}
}
}, action) {
let DnD = Object.assign({}, state.DnD);
let structs = state.structures.slice();
switch (action.type) {
case "STOP_DRAG_CONTENT":
let cindex_source;
let index_source;
let cindex_target;
let index_target;
let foundTarget = false;
let foundSource = false;
structs.map(function (struct, index) {
struct.content.map(function (content, cindex) {
if(content.id === DnD.dragOverContent.props.id) {
cindex_target = cindex;
index_target = index;
foundTarget = true;
}
if(content.id === DnD.dragContent.props.id) {
cindex_source = cindex;
index_source = index;
foundSource = true;
}
});
});
console.log(state);
console.log(index_source);
console.log(cindex_source);
console.log(index_target);
console.log(cindex_target);
if(index_source !== undefined && cindex_source !== undefined && index_target !== undefined && cindex_target !== undefined) {
let copy = structs[index_source].content.slice(cindex_source, cindex_source+1)[0];
copy.content = DnD.content;
structs[index_source].content.splice(cindex_source, 1);
if (DnD.dragContentTop) {
structs[index_target].content.splice(cindex_target+1, 0, copy);
} else {
structs[index_target].content.splice(cindex_target, 0, copy);
}
}
DnD = {
dragContent: null,
dragOverContent: null,
dragContentTop: true,
dragStructure: null,
dragOverStructure: null,
dragStructureTop: true,
content: null,
mousepositon: {}
};
return {...state, DnD: DnD, structures: structs};
}
return state
}
It's not that it is printing the rearranged version before it happens. It is that it is printing an object that you are mutating. By the time you look at the object in the console the mutation has already occurred.
The use of splice is mutating.
structs[index_source].content.splice(cindex_source, 1);
if (DnD.dragContentTop) {
structs[index_target].content.splice(cindex_target+1, 0, copy);
} else {
structs[index_target].content.splice(cindex_target, 0, copy);
}
EDIT:
The above mutation is actually mutating the nested properties of state.structures. This is happening because .slice() returns a shallow copy of the original object.
The slice() method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included). The original array will not be modified.
The objects in the shallow copy are just pointers to the objects in state.structures. So when you use .splice(), you mutate those referenced values.
Here is a snippet to illustrate this. Run it an look at the console.log.
const people = [
{
name: "Joe",
age: "52"
},
{
name: "Sally",
age: "48"
}
];
const clonedPeople = people.slice();
console.log("people === clonedPeople: ", people === clonedPeople);
console.log("people[0] === clonedPeople[0]: ", people[0] === clonedPeople[0]);
const deeplyClonedPeople = JSON.parse(JSON.stringify(people));
console.log("people[0] === deeplyClonedPeople[0]: ", people[0] === deeplyClonedPeople[0]);
Hope this helps!

This.setState causes the browser to hang + Reactjs

var columns = []
for (var key in this.props.col)
{
if (this.state.isEditing){
columns.push(<td key = {key.id}><input ref = "txt" type = "text" value = { this.state.itemValue } onChange = { this.onTextChange.bind(this) } /></td>)
}
else
{
columns.push(<td key = {key.id}>{ this.props.col[key] }</td>)
// this.setState({
// itemValue: key,
// isEditing: false
// })
console.log(key)
}
console.log(key);
}
return columns
Every time I uncomment this lines:
// this.setState({
// itemValue: key,
// isEditing: false
// })
It causes the browser to hang. And a modal message shows up on the browser which says "a script on this page may be busy" and asking me whether to stop the script or continue. Thanks.
Every time you 'setState', your component will rerender, and I guess your function is called during the rendering phase (since it seems to build columns)

Resources