got undefined to passing data react-redux - javascript

i always got undefined when i click the submit button on modalAction
if I do console.log (projectData) in my action modal to see all the data, how do I pass project data from in modalAction to projectAction?
/src/view/projectList.js
const ProjectList = () => {
const dispatch = useDispatch()
const project = useSelector(state => state.project)
const modal = useSelector(state => state.modal)
const category = useSelector(state => state.category)
// Open New Project Modal
const handleOpenProjectModal = () => {
dispatch(openModal(category.categories, project.data))
}
return (
<Button
label="Add Project"
onClick={()=> handleOpenProjectModal()}
primary={true}
/>
)
/src/store/action/modalAction.js
export const openModal = (categoryList, projectData) => dispatch => {
dispatch({
<Button
label='Submit'
onClick={() => dispatch(createProject(projectData))}
primary={true}
/>
})
/src/store/action/projectAction.js
export const createProject = (data) => dispatch => {
try {
instance.post('/project', data)
.then(res => {
dispatch({
type: CREATE_PROJECT,
message: res.data.message
})
instance.get('/project')
.then(res => {
dispatch({
type: GET_PROJECTS,
payload: res.data.data
})
})
dispatch({type: CLOSE_MODAL})
})
} catch (error) {
dispatch({
type: PROJECTS_ERROR,
payload: error,
})
}
}

Related

How to make react component call an axios HTTP request

I am trying to make a section for my website with a news bar that contains snippets of update posts for my site. To do so, I have successfully created the data schema, routing on my backend for post and get requests. I am routing requests on the client server using axios for my XMLHTTPRequests, Redux for my global state store, and cors. Using my NewsBar component, I wrap my NewsPosts component, which is a collection of rendered NewsPost components.
NewsBar component:
function useQuery() {
return new URLSearchParams(useLocation().search);
}
const NewsBar = () => {
const classes = useStyles();
const query = useQuery();
const page = query.get('page') || 1;
const searchQuery = query.get('searchQuery');
const [currentId, setCurrentId] = useState(0);
console.log(`NewsBar: ${useLocation().search} | query=>${query}`);
console.log(`searchquery: ${searchQuery}`);
return (
<>
<Grow in>
<Grid container direction={'row'} className={classes.newsBar} justifyContent='center'>
<Typography variant='h3'>News Bar</Typography>
<Grid item>
<NewsPosts setCurrentId={setCurrentId} />
</Grid>
</Grid>
</Grow>
</>
)
}
export default NewsBar;
NewsPosts component:
const NewsPosts = ({ setCurrentId }) => {
const { newsPosts, isLoading } = useSelector((state) => state.newsPosts);
const classes = useStyles();
newsPosts.map((newsPost) => {
console.log(newsPost);
})
console.log(new Date().toISOString());
console.log(`newsPosts array: ${typeof newsPosts} ${newsPosts}`)
if (!newsPosts.length && !isLoading) return 'No news posts.';
return (
isLoading ? <LinearProgress /> : (
<Grid container alignItems='stretch' spacing={3}>
{newsPosts?.map((newsPost) => (
<Grid key={newsPost._id} item xs={12} sm={12} md={12} lg={12}>
<NewsPost newsPost={newsPost} setCurrentId={setCurrentId}/>
</Grid>
))}
</Grid>
)
);
};
export default NewsPosts;
I added console logging for each of my routing actions and methods, and unfortunately it seems as though I get an empty array of type Object instead of the page of documents I am supposed to get. Within my console, the only logs that output are from NewsPosts.js.
NewsBar: | query=>
NewsBar.js:27 searchquery: null
NewsPosts.js:17 2022-12-01T20:36:08.958Z
NewsPosts.js:18 newsPosts array: object
On top of that, I checked my network requests and none were made. Could someone attempt to tell me why this is?
Axios code as per request:
import { START_LOADING, END_LOADING, FETCH_POST, FETCH_ALL, DELETE, CREATE } from "../constants/actionTypes";
import * as api from '../api/index.js';
//CREATE ACTIONS -> should follow the standard XMLHTTPRequest operation
export const getNewsPost = (id) => async (dispatch) => {
try {
console.log('actions: action getNewsPost was called');
dispatch({ type: START_LOADING })
const { data } = await api.fetchNewsPost(id);
dispatch({type: FETCH_POST, payload: { newsPost: data }});
console.log(`got post ${data}`);
} catch (error) {
console.log(error);
}
};
export const getNewsPosts = (page) => async (dispatch) => {
try {
console.log('actions: action getNewsPosts was called');
dispatch({ type: START_LOADING });
const {data : {data, currentPage, numberOfPages }} = await api.fetchNewsPosts(page);
dispatch({ type: FETCH_ALL, payload: { data, currentPage, numberOfPages }});
dispatch({ type: END_LOADING });
} catch (error) {
console.log(error);
}
};
export const createNewsPost = (newsPost, history) => async (dispatch) => {
try {
console.log('actions: action createNewsPosts was called');
dispatch({ type: START_LOADING });
const { data } = await api.createNewsPost(newsPost);
dispatch({ type: CREATE, payload: data });
history.push(`/newsPosts/${data._id}`);
} catch (error) {
console.log(error);
}
};
export const deleteNewsPost = (id) => async (dispatch) => {
try {
console.log('actions: action deleteNewsPost was called');
await await api.deletePost(id);
dispatch({ type: DELETE, payload: id });
} catch (error) {
console.log(error);
}
};
index.js
import axios from 'axios';
const API = axios.create({ baseURL: 'http://localhost:5000' });
API.interceptors.request.use((req) => {
if (localStorage.getItem('profile')) {
req.headers.Authorization = `Bearer ${JSON.parse(localStorage.getItem('profile')).token}`;
}
return req;
});
export const fetchPost = (id) => API.get(`/posts/${id}`);
export const fetchPosts = (page) => API.get(`/posts?page=${page}`);
export const fetchPostsByCreator = (name) => API.get(`/posts/creator?name=${name}`);
export const fetchPostsBySearch = (searchQuery) => API.get(`/posts/search?searchQuery=${searchQuery.search || 'none'}&tags=${searchQuery.tags}`);
export const createPost = (newPost) => API.post('/posts', newPost);
export const likePost = (id) => API.patch(`/posts/${id}/likePost`);
export const comment = (value, id) => API.post(`/posts/${id}/commentPost`, { value });
export const updatePost = (id, updatedPost) => API.patch(`/posts/${id}`, updatedPost);
export const deletePost = (id) => API.delete(`/posts/${id}`);
export const signIn = (formData) => API.post('/user/signin', formData);
export const signUp = (formData) => API.post('/user/signup', formData);
export const fetchNewsPost = (id) => API.get(`/news/${id}`);
export const fetchNewsPosts = (page) => API.get(`/news?page=${page}`);
export const createNewsPost = (newNewsPost) => API.post('/news', newNewsPost);
export const deleteNewsPost = (id) => API.delete(`/news/${id}`);

Updating useReducer state from another function - React Pagination

I'm making a movie and I want to add pagination in the MoviesFromGenre component. Initially, MoviesFromGenre gets rendered based on the id from GenresList.
I want to add Pagination but I don't know how to update the state in useReducer when I click next/prev buttons?
import React, { useEffect, useReducer, useState } from 'react';
import { useParams } from 'react-router-dom'
import axios from 'axios';
import { API_URL, API_KEY } from '../api/config.js';
import Movies from './Movies'
const initialState = {
loading: true,
error: '',
movies: []
};
const reducer = (state, action ) => {
switch(action.type) {
case 'FETCH_SUCCESS':
return {
loading: false,
movies: action.payload,
error: '',
};
case 'FETCH_ERROR':
return {
loading: false,
movies: [],
error: 'Error'
};
default:
return state;
}
};
function MoviesFromGenre () {
const [state, dispatch] = useReducer(reducer, initialState);
const { id } = useParams();
const [pageNumber, setPageNumber] = useState(1)
useEffect(() => {
axios
.get(
`${API_URL}discover/movie?api_key=${API_KEY}&language=en-US&with_genres=${id}`
)
.then(response => {
dispatch({
type: 'FETCH_SUCCESS',
payload: response.data
})
})
.catch(err => {
dispatch({
type: 'FETCH_ERROR'
})
})
}, [])
const nextPage = () => {
axios
.get(
`${API_URL}discover/movie?api_key=${API_KEY}&language=en-US&with_genres=${id}&page=${pageNumber}`
)
.then(response => {
console.log(response.data)
})
setPageNumber(pageNumber+1)
}
const prevPage = () => {
axios
.get(
`${API_URL}discover/movie?api_key=${API_KEY}&language=en-US&with_genres=${id}&page=${pageNumber}`
)
.then(response => {
console.log(response.data)
})
setPageNumber(pageNumber-1)
}
return (
<div>
<Movies state={state}/>
<button onClick={prevPage}>Prev</button>
<button onClick={nextPage}>Next</button>
</div>
)
}
export default MoviesFromGenre;
I created a repository on GitHub.
I want to update the movies state when I click on next or prev buttons.
A Reddit user managed to solve my problem.
He suggested that I include pageNumber as a dependency in my useEffect hook, so it will run whenever pageNumber changes.
function MoviesFromGenre () {
const [state, dispatch] = useReducer(reducer, initialState);
const { id } = useParams();
const [pageNumber, setPageNumber] = useState(1)
useEffect(() => {
axios
.get(
`${API_URL}discover/movie?api_key=${API_KEY}&language=en-US&with_genres=${id}&page=${pageNumber}`
)
.then(response => {
dispatch({
type: 'FETCH_SUCCESS',
payload: response.data
})
})
.catch(err => {
dispatch({
type: 'FETCH_ERROR'
})
})
}, [pageNumber])
const nextPage = () => {
setPageNumber(pageNumber+1)
}
const prevPage = () => {
setPageNumber(pageNumber-1)
}
//....
}

change variable value with axios, useeffect, and usestate

i'm newbie here, i'm stuck. i want to change value from false to true, to stop shimmering when data sucessfully to load.
i have action like this
import axios from "axios";
import { CONSTANT_LINK } from "./constants";
import { GET } from "./constants";
import { ERROR } from "./constants";
import { connect } from 'react-redux';
export const addData = () => {
return (dispatch) => {
axios
.get(CONSTANT_LINK)
.then((res) => {
dispatch(addDataSuccess(res.data));
})
.catch((err) => {
dispatch(errorData(true));
console.log("error");
});
};
};
const addDataSuccess = (todo) => ({
type: GET,
payload: todo,
});
const errorData = (error) => ({
type: ERROR,
payload: error,
});
and this is my homepage which influential in this matter
const [shimmerValue, setShimmerValue] = useState(false)
useEffect(() => {
setShimmerValue(true)
dispatch(addData());
}, []);
<ShimmerPlaceholder visible={shimmerValue} height={20}>
<Text style={styles.welcomeName}>Welcome,Barret</Text>
</ShimmerPlaceholder>
i dont understand how it works
You can pass callback like this
const [shimmerValue, setShimmerValue] = useState(false);
const updateShimmerValue = () => {
setShimmerValue(true);
}
useEffect(() => {
// setShimmerValue(true) // remove this from here
dispatch(addData(updateShimmerValue)); // pass callback as param here
}, []);
Callback call here like
export const addData = (callback) => {
return (dispatch) => {
axios
.get(CONSTANT_LINK)
.then((res) => {
....
callback(); // trigger callback like this here
})
.catch((err) => {
....
});
};
};
you can use it:
const [shimmerValue, setShimmerValue] = useState(false)
useEffect(() => {
setState(state => ({ ...state, shimmerValue: true }));
dispatch(addData());
}, [shimmerValue]);

Why is the array in my redux reducer not available from another component after a redirect to another page of my app?

I have two separate components. I want to have a button that when clicked on will add an element to an array in my reducer and redirect to another component, this component that gets redirected to needs to render the data that was just added to the array. The page redirects to the component I want but the data does not load and the console.logs don't show anything.
This is the component that has the redirect button. On this component the console.log(socialNetworkContract.members[0]) shows the string I expect.
const Posts = () => {
const dispatch = useDispatch();
const getProfile = async (member) => {
const addr = await dispatch({ type: 'ADD_MEMBER', response: member })
console.log(member)
window.location.href='/member'
console.log('----------- member------------')
console.log(socialNetworkContract.members[0])
}
const socialNetworkContract = useSelector((state) => state.socialNetworkContract)
return (
<div>
{socialNetworkContract.posts.map((p, index) => {
return <tr key={index}>
<button onClick={() => getProfile(p.publisher)}>Profile</button>
</tr>})}
</div>
)
}
export default Posts;
This is my reducer
import { connect, useDispatch, useSelector } from "react-redux";
let init = {
posts:[],
post:{},
profiles:[],
profile:{},
members:[],
member:{}
}
export const socialNetworkContract = (state = init, action) => {
const { type, response } = action;
switch (type) {
case 'ADD_POST':
return {
...state,
posts: [...state.posts, response]
}
case 'SET_POST':
return {
...state,
post: response
}
case 'ADD_PROFILE':
return {
...state,
profiles: [...state.profiles, response]
}
case 'SET_PROFILE':
return {
...state,
profile: response
}
case 'ADD_MEMBER':
return {
...state,
members: [...state.members, response]
}
case 'SET_MEMBER':
return {
...state,
member: response
}
default: return state
}
};
and this is the component that is redirected to. this just says undefined in console.log(socialNetworkContract.members[0])
const Member = () => {
const [user, setUser] = useState({});
const socialNetworkContract = useSelector((state) => state.socialNetworkContract)
useEffect(async()=>{
try {
const pro = socialNetworkContract.members[0]
console.log(socialNetworkContract.members[0])
await setUser(pro)
console.log(socialNetworkContract.members[0])
} catch (e) {
console.error(e)
}
}, [])
I have the route set in Routes.js as
<Route path="/member" exact component={Member} />
Use history.push('/') instead of window.location.href which will reload your whole page and you will lost your local state data.
const {withRouter} from "react-router-dom";
const Posts = (props) => {
const dispatch = useDispatch();
const getProfile = async (member) => {
const addr = await dispatch({ type: 'ADD_MEMBER', response: member })
console.log(member)
props.history.push('/member');
console.log('----------- member------------')
console.log(socialNetworkContract.members[0])
}
const socialNetworkContract = useSelector((state) => state.socialNetworkContract)
return (
<div>
{socialNetworkContract.posts.map((p, index) => {
return <tr key={index}>
<button onClick={() => getProfile(p.publisher)}>Profile</button>
</tr>})}
</div>
)
}
export default withRouter( Posts );

Wait For The Result Of Dispatch (React-Redux)

Lets say I have a function that calls an api and get user data ,
export function submitLogin({email, password})
{
return (dispatch) =>
jwtService.signInWithEmailAndPassword(email, password)
.then((user) => {
debugger;
dispatch(setUserData(user));
return dispatch({
type: LOGIN_SUCCESS
});
}
)
.catch(error => {
debugger;
return dispatch({
type : LOGIN_ERROR,
payload: error
});
});
}
Now this is how I call this
function handleSubmit(model)
{
dispatch(authActions.submitLogin(model));
}
And Form
<Formsy
onValidSubmit={handleSubmit}
onValid={enableButton}
onInvalid={disableButton}
ref={formRef}
className="flex flex-col justify-center w-full"
>
Now please let me know how can I read the type sent by dispatch (as soon it receive response from an Api) inside submitLogin function also I would like to redirect to url if type is LOGIN_SUCCESS
const handleSubmit = async (model) => {
await dispatch(authActions.submitLogin(model));
}
export submitLogin = ({email, password}) => {
return async (dispatch) =>
await jwtService.signInWithEmailAndPassword(email, password)
.then((user) => {
debugger;
dispatch(setUserData(user));
return dispatch({
type: LOGIN_SUCCESS
});
}
)
.catch(error => {
debugger;
return dispatch({
type : LOGIN_ERROR,
payload: error
});
});
}
Try this way
function Example({ navigation }) {
const redirectCallback = () => {
// redirect here
navigation.navigate('Your Route');
}
function handleSubmit(model)
{
dispatch(authActions.submitLogin( model, () => redirectCallback() ) );
}
return(
<Formsy
onValidSubmit={handleSubmit}
onValid={enableButton}
onInvalid={disableButton}
ref={formRef}
className="flex flex-col justify-center w-full"
>
)
}
export function submitLogin({email, password}, callback)
{
return (dispatch) =>
jwtService.signInWithEmailAndPassword(email, password)
.then((user) => {
debugger;
dispatch(setUserData(user));
return dispatch({
type: LOGIN_SUCCESS,
callback: callback; // send callback here
});
}
)
.catch(error => {
debugger;
return dispatch({
type : LOGIN_ERROR,
payload: error
});
});
}
Create reducer and handle type LOGIN_SUCCESS
const reducer = (state = { isLoggedIn: false }, action) => {
switch (action.type) {
case LOGIN_SUCCESS:
action.callback(); call here
return state;
default:
return state;
}
};

Categories

Resources