Cant change boolean value in object (React) - javascript

This is my state object. I am trying to change "isVisible" value from "HideUser" case that i provided below. But output is allways gives me same isVisible value. And i cant flip it. I would appreciate for any help.
Note: when i say isVisible=false, it works. And isVisible value is allways same when i print.
state={
users:[
{
id:1,
isim:"Muhammedcan Pirinççi",
okul:"Marmara",
maaş:"a4000",
isVisible:true
},
{
id:2,
isim:"Suat Pirinççi",
okul:"Marmara",
maaş:"a10000",
isVisible:true
}
],
dispatch: action => {
this.setState(state=>reducer(state,action))
}
}
HideUser case:
case "HIDE_USER":
return{
...state,
users: state.users.map(user => {
if (user.id===action.payload) {
user.isVisible=!user.isVisible
return user
}
else{
return user
}
})
}

Related

how to push into nested array in reducer

Above image shows what happens when I trying to dispatch a reply action.
Currently trying to push the input field value etc into the replyComments...but it is still empty even when dispatching this action.... the reducer is checking the majorIndex first and then the minorIndex, from there it should push it into the replyComments. Any one knows how I can fix this?
Link to working Codesandbox
case types.REPLY_COMMENT: {
return {
...state,
enableToggleComment: true,
imageData: state.imageData.map(image => image.id === action.majorIndex ?
{
...image,
comments: {
[action.minorIndex]: {
replyComments: [...image.comments.replyComments, { comment: action.newComment, likeComment: image.toggle, enableReply: false }]
}
}
} : image
)
}
}
EDIT:
I know noticed it's due to a missing key to [action.minorIndex] and when using the ? operator and want to return an object you should add the parenthesis, otherwise you are declaring a scope (like i did whoops)
case types.REPLY_COMMENT: {
return {
...state,
enableToggleComment: true,
imageData: state.imageData.map(image => image.id === action.majorIndex ?
({
...image,
comments: {
[action.minorIndex]: {
replyComments: [...image.comments[action.minorIndex].replyComments, { comment: action.newComment, likeComment: image.toggle, enableReply: false }],
}
}
}) : image
)
}
}
I've only added action.replyText but you should be able to add the rest now
case types.REPLY_COMMENT: {
return {
...state,
enableToggleComment: true,
imageData: state.imageData.map(image =>
image.id === action.generalIndex
? {
...image,
comments: image.comments.map((comment, i) =>
i === action.majorIndex
? {
...comment,
replyComments: [
...comment.replyComments,
action.replyText
]
}
: comment
)
}
: image
)
};
}

How do I properly update an item in my array in redux without mutating?

const state = [
{
list: []
}
];
The list is a list of student objects, for example:
list: [
{ id: 1, name: "Mark", attendance: true },
{ id: 2, name: "John", attendance: false }
]
I have a button that triggers a post request to an API to change attendance to true. Post request returns the student object that was changed as in e.g.:
{ id: 2, name: "John", attendance: true }
This works fine and if no errors, will dispatch ATTENDANCE_SUCCESS.
Now, with this kind of set-up:
export function students(state, action) {
let latestState = state[state.length - 1],
newState = Object.assign({}, latestState);
switch (action.type) {
case "ATTENDANCE_SUCCESS":
if (action.res.errorCode == 0) {
// Need to change redux state 'attendance' value to true for a student with ID returned from the POST request
}
}
Initially, I did:
const studentChanged = newState.list.find(function(student) {
return (
student.id ===
action.res.data.id
);
});
studentChanged.attendance = true;
But it mutates the state in the redux store (although I am not sure how it's exactly happening since I assumed newState is already a copy).
What's the proper way?
The following would update a single item in the array. The critical aspect here is that if the id of the item does not match the id from the action payload, it returns the item unaltered, otherwise it updates the attendance property. Array.prototype.map returns a new array so it would be immutable.
export function students(state, action) {
switch (action.type) {
case "ATTENDANCE_SUCCESS":
if (action.res.errorCode == 0) {
return state.map(student => {
// we want to leave non matching items unaltered
if (student.id !== action.res.data.id) {
return student;
}
return { ...student, attendance: true };
});
}
return state;
default:
return state;
}
}
Here is a StackBlitz to demonstrate the functionality.
Hopefully that helps!

Vue data not getting overwritten by a eventHub call

I cant figure out, why my variable inside data() isnt getting overwritten.
Code looks like this:
export default {
props: ["store", "link", "index", "isStoreOpen"],
data() {
return {
hovered_over_icon: false,
window_width: window.innerWidth,
opened: null
}
},
methods: {
toggleRestaurantView() {
this.link()
},
check_for_breaks(text){
return text.replace(/\*break\*/g, '<br/>');
},
change_state(state){
this.opened = state
}
},
computed: {
url() {
return ((this.store) ? `https://www.google.com/maps/dir/Current+Location/${this.store.address.location.lat},${this.store.address.location.lon}` : '#')
},
isOpen() {
return this.store.openNow;
}
},
created(){
eventHub.$on('restaurantOpened', (state) => this.change_state(state));
eventHub.$on('changeFilteredRestaurantsAfterRestaurantVisit', (state) => this.store = state);
}
}
</script>
But when I log the this.opened after reassigning new value, I get the correct one, however when I check Vue console, it stayed on null.
Even if I do this.$forceUpdate() it doesnt get updated.
Never happened this to me in my Vue career so far, a bit confused.

Using spread operator to setState in multiple succession

I have some values stored in local storage. When my component mounts, I want to load these values into the state. However, only the last property being added is added to the state. I've checked the values on my localStorage, and they are all there. Furthermore, when I log the variables (desc, pic or foo) in the condition block, they are there.
I thought at first each subsequent if block is re-writing the state, but this is not the case as I am using the spread operator correctly (I think!), adding the new property after all pre-existing properties.
I think the problem is that the code in the last if block is running before the state is set in the first if block. How do I write the code so I get all three properties from my local storage into the state?
//what I expect state to be
{
textArea: {
desc: 'some desc',
pic: 'some pic',
foo: 'some foo'
}
}
//what the state is
{
textArea: {
foo: 'some foo'
}
}
componentDidMount () {
const desc = window.localStorage.getItem('desc');
const pic = window.localStorage.getItem('pic');
const foo = window.localStorage.getItem('foo');
if (desc) {
console.log(desc) //'some desc'
this.setState({
...this.state,
textArea: {
...this.state.textArea,
desc: desc,
},
}, ()=>console.log(this.state.textArea.desc)); //undefined
}
if (pic) {
console.log(pic) //'some pic'
this.setState({
...this.state,
textArea: {
...this.state.textArea,
pic: pic,
},
}, ()=>console.log(this.state.textArea.pic)); //undefined
}
if (foo) {
console.log(foo) //'some foo'
this.setState({
...this.state,
textArea: {
...this.state.textArea,
foo: foo,
},
}, ()=>console.log(this.state.textArea.foo)); //'some foo'
}
}
You are likely being caught by React batching setState calls by shallow-merging the arguments you pass. This would result in only the last update being applied. You can fix this by only calling setState once, for example:
componentDidMount () {
const desc = window.localStorage.getItem('desc');
const pic = window.localStorage.getItem('pic');
const foo = window.localStorage.getItem('foo');
this.setState({
textArea: Object.assign({},
desc ? { desc } : {},
pic ? { pic } : {},
foo ? { foo } : {}
)
});
}
The other version is to pass an update function to setState rather than an update object, which is safe to use over multiple calls. The function is passed two arguments: the previous state, and the current props - whatever you return from the function will be set as the new state.
componentDidMount () {
const desc = window.localStorage.getItem('desc');
const pic = window.localStorage.getItem('pic');
const foo = window.localStorage.getItem('foo');
this.setState(prevState => {
if (desc) {
return {
textArea: {
...prevState.textArea,
desc
}
}
} else {
return prevState;
}
});
// Repeat for other properties
}
It's a little more verbose using this approach, but does offer the opportunity to extract state updating functions outside of your component for testability:
// Outside component
const updateSubProperty = (propertyName, spec) => prevState => {
return {
[propertyName]: {
...prevState[propertyName],
...spec
}
}
}
const filterNullProperties = obj => {
return Object.keys(obj).reduce((out, curr) => {
return obj[curr] ? { ...out, [curr]: obj[curr] } : out;
}, {});
}
componentDidMount () {
this.setState(updateSubProperty("textArea",
filterNullProperties(
desc: window.localStorage.getItem('desc'),
pic: window.localStorage.getItem('pic'),
foo: window.localStorage.getItem('foo')
)
));
}
This way adds some complexity, but (in my opinion) gives a really readable component where it is clear to our future selves what we were trying to achieve.

Need to append data in the array in reducer of redux

I am doing pagination where i will be getting data for each page click.I want to append the data with the previous values.Here is my current code.Have no idea to do it.
const InitialProjects={
projectList:[],
error:null,
loading:false
}
export const projects=(state=InitialProjects,action)=>{
switch(action.type){
case ActionTypes.FETCH_PROJECTS:
return Object.assign({},state,{
projectList:[],error:null,loading:true
})
case ActionTypes.FETCH_PROJECTS_SUCCESS:
return {
projectList:action.payload
}
case ActionTypes.FETCH_PROJECTS_FAILURE:
return Object.assign({},state,{
projectList:["not-found"],error:action.payload.message||action.payload.status,loading:false
})
default:
return state;
}
}
My first response will look something like this
[
{
Id:0,
Name:india
},
{
Id:1,
Name:bang
},
{
Id:3,
Name:us
},
{
Id:5,
Name:uk
}
]
second response will be like this
[
{
Id:8,
Name:india
},
{
Id:12,
Name:bang
},
{
Id:19,
Name:us
},
{
Id:35,
Name:uk
}
]
Please do note that the id field might not be consecutive.
I want something like this in my redux
projectList:
0(pin): {Id:1,Name:'dewd'}
1(pin): {Id:2,Name:'tyytg'}
2(pin): {Id:5,Name:'xsx'}
3(pin): {Id:4,Name:'tyyt'}
4(pin): {Id:10,Name:'xsx'}
5(pin): {Id:17,Name:'xsx'}
Appreciate any help.Thanks
You can spread the results on each success.
case ActionTypes.FETCH_PROJECTS:
return {
...state,
error: null,
loading: true,
}
case ActionTypes.FETCH_PROJECTS_SUCCESS:
return {
...state,
projectList: [...state.projectList, ...action.payload]
}
Looks like the object spread operator doesn't work in your case. So an ES5 version of the answer for you would be.
case ActionTypes.FETCH_PROJECTS_SUCCESS:
return Object.assign(
{},
state,
{
projectList: state.projectList.concat(action.payload)
});
This copies all the previous values from state into a new object by using Object.assign then overwrites a new projectList property by concatenating old values from state.projectList and new ones from action.payload.
Hope it helps!

Categories

Resources