React:How to submit data to a modal? - reactjs

I am creating a job list. In this job list, we have a button to open modal for enter the detail of a job. However, when I pass a default job object with default value to the modal, the modal cannot show the default job value.
Because some default attributes are came from remote API, so in the JobList component, I use the useEffect hook to retrieve data from remote API.
Would you tell me what's going on?
My code is resided here.

I checked your code and there is a logical error.
You need to add break; after addJob case statement in JobList.js.
Because of that, defaultJobObj is reiniting as undefined object.
-- ADDITION --
You need to handle defaultJobObj prop update in JobForm component.
You can define a hook and reinit items in reducer.
let reducer = (state, action) => {
let result = { ...state };
switch (action.type) {
case "reinit":
result.job = defaultJobObj;
break;
default:
break;
}
return result;
};
useEffect(() => {
updateItems({
"type":"reinit"
})
}, [defaultJobObj])

Maybe you can use state management like Redux/React Context to pass the values to your modal

Related

React DOM not updated when prop from redux store changes

This is driving me crazy for hours now... I have a module that displays a list that is fetched from a server and loaded into the redux store on button press. That works properly. I mention this as this is the reason why I don't understand the following behavior.
This object array from the store is mapped into my component with
const mapStateToProps = (state) => {
return {
extracted_templates: state.extracted_templates
}
}
And used in the render() as follows... I removed some other DOM parts to keep it simple
render(){
return(
<div className="main-container">
{Object.values(this.props.extracted_templates).length > 0 ?
<ExtractedTemplatesList templates={Object.entries(this.props.extracted_templates)} clickHandler={this.clickHandler} /> : '' }
</div>
);
}
The clickHandler modifies the store using the same action as the fetch function uses.
clickHandler(action, id, parent){
console.log(action+" "+parent)
switch(action){
case 'dismiss':
let new_template_list = this.props.extracted_templates
delete new_template_list[id]
// console.log(new_template_list)
this.props.dispatch(setExtractedTemplates(new_template_list))
break;
default:
break;
}
}
Everything is called correctly, the store updates correctly (as I can see in my web-dev console) but this time the DOM doesn't get updated.
For completeness, here's the action and the reducer implementation
action:
export const setExtractedTemplates = (templates) => ({
type: actions.SET_EXTRACTED_TEMPLATES,
payload: templates
});
reducer:
case actions.SET_EXTRACTED_TEMPLATES:
console.log({action})
return {
...state,
extracted_templates: action.payload
}
You're mutating the existing data, and you're putting the exact same object back into the store:
let new_template_list = this.props.extracted_templates
delete new_template_list[id]
this.props.dispatch(setExtractedTemplates(new_template_list))
Both of those are bugs. You should never mutate data from the store, and the result of an action should be new data in the store.
This is one of the reasons why we recommend putting as much logic as possible into reducers. Also, you should be using our official Redux Toolkit package, which would both catch this accidental mutation here, and simplify the update logic in a reducer.
Try this:
clickHandler(action, id, parent){
console.log(action+" "+parent)
switch(action){
case 'dismiss':
let new_template_list = {...this.props.extracted_templates} //make a new copy
delete new_template_list[id]
// console.log(new_template_list)
this.props.dispatch(setExtractedTemplates(new_template_list))
break;
default:
break;
}
}
You modified the same object saved in the redux store. This is potentially dangerous because you changed the state without using a reducer. When React did the shallow comparison, it didn't see difference so UI was not updated. You can make a copy before save it to store.
Further more you can modify your reducer in this way:
case actions.SET_EXTRACTED_TEMPLATES:
console.log({action})
return {
...state,
extracted_templates: [...action.payload] //make a new copy
}

How update array in real time not after refresh page (Redux)

I'm doing to do list and want do the functional when you click on button "done" the text will be crossed out.
I done array with deals which have fields 'text' and 'isDone'. isDone by default is false, when on click I get all array with deals and text deal in which you click. Than I map array with deals that I get and compare text from click deal and text in all deals in array.If they the same I change isDone from false to true.
But it update if i refresh the page and I need that it updata on click.
I use redux-persist and all states put into localStorage
button
<button onClick={()=>this.props.done(this.props.deals,value.text)}>Done</button>
Action
export function done(newDeals,dealText){
return(dispatch) =>{
newDeals.map(value=>{
if(value.text === dealText){
value.isDone = !value.isDone
}
})
dispatch(doneDeal(newDeals));
}
}
export function doneDeal(newDeals){
return{
type: DONE,
newDeals
}
}
Reducer
export default function toDoList(state = initialState, action){
switch(action.type){
case DONE:
return {
...state, deals: action.newDeals
}
default:
return state
}
}
I delete code that have no sense for this example, but need more info please ask I will tell
Thank you!
You have to use mapStateToProps to get the recently updated state from Redux state.
All what you need is to wrap your component export with the following:
const mapStateToProps = state => ({
deals: state.deals
});
export default connect(mapStateToProps)(ComponentName);
By this you are getting the needed state data from the initialState you have defined in your reducer and the reference to these data is the "deals" which can be used as normal prop: this.props.deals in case of class component OR as parameter through descructureing ({deals}) in case of functional component.
I don't know the full structure of the component because you haven't added it but this is the correct way to get the state from redux.
To make things more clear for you, you can read more through this link:
https://react-redux.js.org/using-react-redux/connect-mapstate
UPDATE: I figured out your problem after adding your reply.
The problem is with your code here:
<button onClick={()=>this.props.done(this.props.deals,value.text)}>Done</button>
You are getting the deals directly from the Redux global state and when dispatching your action you are passing them directly in the dispatch method. So your component is not able to listen to any change happening to your component. You need to save the deals in your local state:
state = {
deals: this.props.deals
}
and change the onClick to the following:
<button onClick={()=>this.props.done(this.state.deals,value.text)}>Done</button>

How can I update my redux state correctly?

I am facing a problem, I am new to Redux, and I am just playing around with it, So I have a problem, I created a data json file, I get the data from it in my reducer, and everything works fine, here is my reducer :
import update from "immutability-helper";
import data from "../../../../data";
export default function notificationsReducer(state, action) {
switch (action.type) {
case "NOTIFICATIONS_EDIT_TO_FOLLOW":
return update(state, {
[action.id]: {
follwing: { $set: false }
}
});
break;
case "NOTIFICATIONS_EDIT_TO_UNFOLLOW":
return [];
break;
default:
return data.notifications;
}
}
As you can see, in the default part, I return data.notififications, this causes a probleme of course, because the data in the json file does not change, the state does.
When I work on my component and click 'follow' and 'unfollow' and stuffs everything looks fine, but When I click somewhere else outside the component, others actions got dispatched, ( others for different purposes ) and the default part get executed again, so when I open my notifications again all changes I made are gone.
That's my problem, if any explanation from me is needed just ask and I will edit my question.
Any help would be much appreciated.
Recapping from the comments:
In your default case (for all reducers), you need to return the current state of your reducer so that unrelated actions don't interfere with their values:
default:
return state;
You also (if needed) have to set up the initial value of your reducer, in this case the notifications from the data JSON file:
export default function notificationsReducer(state = data, action) {...}

Can I bind store's state with a component in react-redux?

I am Newbie in react-redux, I created a small CRUD application with react-redux, when I click over add button from a child component it takes data from all input boxes and updates my store's array with the help of Reducer.
const initialState = {
itemObjectArr:[] }
My Reducer updates this itemObjectArr, and send it to needy component with the help of connect(mapStateToProps)(NeedyChildComponent) function.
Now the real problem occurs when I try to print state.itemObjectArr on the console.
const mapStateToProps = (state)=>{
console.log(state.itemObjectArr);
return {itemObject:state.itemObjectArrs}}
Above code gives an error on console TypeError: Cannot read property 'itemObjectArrs' of undefined
and if I do console.log(state) it prints objects contained array easily without any error.
I searched for this error but not get anything important, I think this store's state is immutable and when it passes to mapStateToProps function as an argument then mapStateToProps checks changes in state and if it does not get any changes then it returns an error. maybe this is occurring here.
What does your reducer look like? Since the store is returned as undefined in your component, it sounds to me that you haven't defined a default case in your switch statement that returns the initial state before your update action is executed, like:
const myReducer = (state, action) => {
switch (action.type) {
case 'UPDATE_ITEM_OBJECT_ARR': return { itemObjectArr: [ 1, 2, 3] }
default:
return initialState;
}
}

my reducer is executed but state does not update in react

I am using recat redux for my project and in one component I need to update my state but since I am dealing with asynchronous call I need to do the action call in my componentDidUpdate as follows:
componentDidUpdate() {
this.props.updateHamburgerMenu(this.props.Channel.channelIdArr);
}
and here is my action:
export function updateHamburgerMenu(channelIdArr) {
return dispatch => {
dispatch(
{
type: "UPDATE_HAMBURGER_MENU",
payload: {
"channelIdArr":channelIdArr
}
}
);
};
}
and in my reducer I have :
switch (action.type) {
case "UPDATE_HAMBURGER_MENU":
var channelList=state.allChannelList.slice();
channelList.unshift({
"id": channelIdArr[0],
"channelName": "sssssssss",
"status": "Inactive"
});
alert("reducer called");
state.allChannelList=channelList;
break;}
return state;
Now when I run it I can see that the alert is working but state does not update at all.
Also I tried another way as follow:
state={"channelsArr":state.channelsArr,"AllChannels":state.AllChannels,"channelIdArr":state.channelIdArr,"channelLabelForScrolls":[], "latestAction":action.type, "allChannelList":channelList};
break;
This way, it seems that state keep updating and it goes in infinite loop.
It is really confusing, can anyone help? what am I missing?
Update:
When I separate the allChannelList in another reducer it works. So it seems that updating allChannelList in a specific case of componentdidupdate goes to infinite loop and state keep updating itself. BUt I have no idea why it is happenning
in your reducer case statements, you should be returning a new object which represents the state after the current action - you appear to be trying to assign directly to the allChannelList property on the passed in state object.
i.e.
return {
...state,
allChannelList: channelList
};

Resources