Two click for dispatch action Redux - javascript

I use REDUX in my REACTJS application. I want to retrieve the button ID after clicking the button and send it to my store. It's only works after the second click. Can you help me ? My code:
My function :
gotoidee (e) {
let test= this.state.data[e.target.id];
console.log("test" +test.titre);
const action = { type: "SAVE_IDEE_ID", value:this.state.data[e.target.id]};
this.props.dispatch(action);
console.log(this.props.ideeId.titre);
}
const mapStateToProps = (state) => {
return {
ideeId: state.saveIdee.ideeId
}
}
export default connect(mapStateToProps)(liste_idee)
My reducer :
const initialState = { ideeId: [] }
function saveIdee (state = initialState, action) {
let nextState
switch (action.type) {
case 'SAVE_IDEE_ID':
nextState = {
...state,
ideeId: action.value
}
return nextState
default:
return state
}
}
export default saveIdee
My button :
<Button type="submit" id={ideeId} onClick={this.gotoidee}>Marche</Button>

gotoidee (e) {
// check here if the click is happening by putting a console here
let test= this.state.data[e.target.id];
console.log("test" +test);
const action = { type: "SAVE_IDEE_ID", value:test};
this.props.dispatch(action);
}
render(){
console.log(this.props.ideeId); // check the updated value
}

Related

React/Redux - Add element instead of replacing state

I am using https://reactflow.dev/ library and in Redux state when I add a new element rather than add it to the array it replaces the previous item with a new one.
Reducer
import * as types from '../actions/types';
const initialState = {
elements: [],
currentElement: undefined,
};
const flow = (state = initialState, action) => {
switch (action.type) {
case types.ADD_ELEMENT:
return {
...initialState,
elements: initialState.elements.concat(action.payload),
// elements: [...initialState.elements, action.payload],
};
}
}
Action
import { ADD_ELEMENT } from './types';
export const addElement = (node) => (dispatch) => {
dispatch({
type: ADD_ELEMENT,
payload: node,
});
};
DndFLow
const onDrop = (event) => {
event.preventDefault();
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
const type = event.dataTransfer.getData('application/reactflow');
const position = reactFlowInstance.project({
x: event.clientX - reactFlowBounds.left,
y: event.clientY - reactFlowBounds.top,
});
const newNode = {
id: getId(),
type,
position,
data: { label: `${type}` },
};
addElement(newNode);
setElements((es) => es.concat(newNode));
};
You're using initialState in the reducer, instead of the state.
Using the state might fix your issue:
const flow = (state = initialState, action) => {
switch (action.type) {
case types.ADD_ELEMENT:
return {
...state,
elements: state.elements.concat(action.payload),
};
}
}
The state = initialState is correct since that means it will use the initialState by default if state doesn't have any value otherwise, but you shouldn't use the initialState beyond that, unless you want to reset your state to it.

Where to make a toggle action in this react redux code?

I have 2 files here:
App.js and reducer.js
I try to use React & Redux for creating onclick toggle action (ex: background color change).
Can anyone help me to where can I make toggle action in this code? (I made setTimeout action in mapDispatchToProps before and it worked but toggle action not.)
see the code:
App.js
import React, { Component } from "react";
import "./App.css";
import { connect } from "react-redux";
class App extends Component {
render() {
return (
<div>
<button
style={{
backgroundColor: this.props.backgroundColor
}}
>
hello
</button>
<button onClick={this.props.changeTheColor}>change</button>
</div>
);
}
}
const mapStateToProps = state => {
return {
backgroundColor: state.backgroundColor
};
};
const mapDispatchToProps = dispatch => {
return {
changeTheColor: () => {
dispatch({ type: "CHANGE_COLOR" }); //I think something should change here but I have no idea how :(
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
and reducer.js
const initialState = {
backgroundColor: "red"
};
const reducer = (state = initialState, action) => {
const updatedState = { ...state };
if (action.type === "CHANGE_COLOR") {
updatedState.backgroundColor = "yellow"; // I added else/if operation there before and didn't worked :(
}
return updatedState;
};
export default reducer;
does someone has any idea(s) how to make toggle action there?
I want to change button red background color to yellow and toggle back the acton
Change code like this:
<button onClick={() => this.props.changeTheColor(this.props.backgroundColor === 'red' ? 'yellow' : 'red')}>change</button>
const mapDispatchToProps = dispatch => {
return {
changeTheColor: (value) => {
dispatch(changeColor(value));
}
};
};
const changeColor = (value) => {
return {
type: 'CHANGE_COLOR',
value
};
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case "CHANGE_COLOR" : {
return { ...state, backgroundColor : action.value }
}
default:
return state
};

React-Redux:reducer only return initial state

when i using redux in my react app,reducer just return initial state for me.which is always returned the false here.thanks for your answer.
[UPDATE]:
i chaned
let newState = state
to this:
let newState = {...state}
but also reducer returned false
this my reducer:
const initialState = {
modalVisible: false
};
function modalReducer(state = initialState, action) {
let newState = {...state};
switch (action.type) {
case "SHOW":
newState.modalVisible = true;
console.log("Show!");
break;
case "HIDE":
newState.modalVisible = false;
console.log("Hide!");
break;
}
return newState;
}
export default modalReducer;
and this is my component (Svg Viewer component)
import React from "react";
import { connect } from "react-redux";
const SvgViewer = ({
nodesData,
svgFilePath,
modalVisible,
onModalShow,
onModalHide
}) => {
const clickHandler = () => {
onModalShow();
console.log(modalVisible); //return false
onModalHide();
console.log(modalVisible);
};
return (
<div className="unit-schema-container1" key={svgFilePath}>
<object id="svgobject" type="image/svg+xml" data={svgFilePath}></object>
<button onClick={clickHandler}></button>
</div>
);
};
const mapStateToProps = state => {
return { modalVisible: state.modalVisible };
};
const mapDispatchToProps = dispatch => {
return {
onModalShow: () => {
dispatch({ type: "SHOW" });
},
onModalHide: () => {
dispatch({ type: "HIDE" });
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(SvgViewer);
You should try using this. Its easier to read and uses the best practices
const initialState = {
modalVisible: false
};
function modalReducer(state = initialState, action) {
switch (action.type) {
case "SHOW":
return {...state, modalVisible: true }
case "HIDE":
return {...state, modalVisible: false }
default:
return state
}
}
you should return a new state object
let newState = {...state}
I think the problem is in mapStateToprops function, please post your main reducer,
try to edit you mapStateToProps
const mapStateToProps = state => {
return { modalVisible: state.modalVisible.modalVisible };
};

Redux proper send of payload

I'm new to Redux. And I'm trying to create a simple FETCH_ALL_POSTS.
actions
export const fetchPosts = () => async dispatch => {
const response = await jsonPlaceholder.get('/posts');
console.log(response.data)
dispatch({
type: FETCH_ALL_POSTS,
payload: response.data
})
}
posts reducer
export default (state = {}, action) => {
const { type, payload } = action;
switch (type) {
case FETCH_ALL_POSTS:
return {
...state, payload
}
default:
return state
}
}
post list component
const mapStateToProps = state => {
console.log(Object.values(state.posts))
return {
posts: state.posts
}
}
This is working but the data that I'm getting from mapStateToProps is not what I'm expecting.
Result : "array: [ 0:[{},{},{}] ]"
My expected result: "array:[{},{},{}]"
Try this,
const initialState = {
posts: '',
}
export default (state=initialState, action) => {
const { type, payload } = action;
switch (type) {
case FETCH_ALL_POSTS:
return{
posts:state.posts=action.payload.posts
}
default:
return state
}
}

How to handle adding new item or delete existing one in React using Redux

I have a list of products called work items stored on my Redux store and I want to add an action that adds new work item or remove existing one when user picks up a a work item from the ui.
What I have so far is this workItemReducer:
import {
FETCH_WORKITEMS_BEGIN,
FETCH_WORKITEMS_SUCCESS,
FETCH_WORKITEMS_FAILURE,
SELECTED_WORKITEM
} from '../actions/workItemAction';
const initialState = {
workItems: [{"name":'work 1'}, {"name":'work 2'}, {"name":'work 3'}],
workItemsSelected: {},
loading: false,
error: null
};
export default function workItemReducer(state = initialState, action) {
switch(action.type) {
case FETCH_WORKITEMS_BEGIN:
return {
...state,
loading: true,
error: null
};
case FETCH_WORKITEMS_SUCCESS:
return {
...state,
loading: false,
workItems: action.payload.workItems
};
case FETCH_WORKITEMS_FAILURE:
return {
...state,
loading: false,
error: action.payload.error,
workItems: []
};
case SELECTED_WORKITEM:
return {
...state,
workItemsSelected: action.payload.workItem
};
default:
return state;
}
}
and the actions looks as below:
export const FETCH_WORKITEMS_BEGIN = 'FETCH_WORKITEMS_BEGIN';
export const FETCH_WORKITEMS_SUCCESS = 'FETCH_WORKITEMS_SUCCESS';
export const FETCH_WORKITEMS_FAILURE = 'FETCH_WORKITEMS_FAILURE';
export const SELECTED_WORKITEM = 'SELECTED_WORKITEM';
export const fetchWorkItemsBegin = () => ({
type: FETCH_WORKITEMS_BEGIN
});
export const fetchWorkItemsSuccess = workItems => ({
type: FETCH_WORKITEMS_SUCCESS,
payload: { workItems }
});
export const fetchWorkItemsFailure = error => ({
type: FETCH_WORKITEMS_FAILURE,
payload: { error }
});
export const selectedWorkItem = workItem => ({
type: SELECTED_WORKITEM,
payload: { workItem }
});
I have a container component that disptach or call these actions which I am a bit confused where the logic of adding a new one or removing existing one happens, either on the container/smart component or directly in the reducer.
Container component has this method:
onWorkItemSelect = (workItem) => {
this.props.dispatch(selectedWorkItem(workItem));
};
Anyone can help on writing the logic of adding new or remove existing one and where that code should live?
adding this to reducer works thou im not sure if all this code should remain into the reducer:
case SELECTED_WORKITEM:
let arr = [];
if (containsObject(action.payload.workItem, state.workItemsSelected)) {
arr = remove(state.workItemsSelected, action.payload.workItem);
} else {
arr = [...state.workItemsSelected, action.payload.workItem];
}
return {
...state,
workItemsSelected: arr
};
It should be done in the reducer
when adding one you could just spread the current array which you can get from the reducer state
const { workItems } = state;
const { workItem } = action.payload;
return {
// ...other stuff to return
workItems: [...workItems, workItem],
}
to delete one
const { workItems } = state;
const { workItem } = action.payload;
return {
// ...other stuff to return
workItems: workItems.filter(x => x.name === workItem.name),
}

Categories