action.js
import Axios from 'axios';
import { PRODUCT_LIST_FAIL, PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS } from '../constraints/productConstraints';
const listProducts = () => async (dispatch) => {
try {
dispatch({ type: PRODUCT_LIST_REQUEST });
const { data } = await Axios.get('http://localhost:3001/product');
dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data });
}
catch(error) {
dispatch({ type: PRODUCT_LIST_FAIL, payload: error.message });
}
}
export { listProducts }
home.js
const Home = () => {
const productList = useSelector(state => state.productList);
const { products, loading, error } = productList;
const dispatch = useDispatch();
useEffect(() => {
dispatch(listProducts());
return () => {
}
},[]);
}
when I use axios.get('/product') it works but when I use axios.get('http://localhost:3001/product') it shows error GET http://localhost:3001/product net::ERR_CONNECTION_REFUSED don't why I am getting this error API is not hitting
If you haven't already done so, add "proxy": "http://localhost:3001", to your package.json in your React app.
Related
I really seem to have trouble with react and hooks. I know that the problem could be do to react-dom. I am watching a tutorial that does it with 5 and im using 6. I looked at the documentation, but I honestly can't find the issue. It worked for my homepage, but now the product page doesn't work and I honestly couldn't find anything on past answers about this problem. Does anybody have an idea?? Thanks!
import React, {useState, useEffect} from 'react'
import { Link } from 'react-router-dom'
import { Row, Col, Image, ListGroup, Button, Card } from 'react-bootstrap'
import Rating from '../components/Rating'
import Loader from '../components/Loader'
import Message from '../components/Message'
import { useParams } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { listProductDetails } from '../actions/productActions'
function ProductScreen({match}) {
const dispatch = useDispatch()
const productDetails = useSelector(state => state.productDetails)
const {loading, error, product} = productDetails
useEffect(() =>{
dispatch(listProductDetails(match.params.id))
},[])
ProductActions.js:
export const listProductDetails = (id) => async(dispatch) => {
try {
dispatch({type: PRODUCT_DETAILS_REQUEST})
const { id } = useParams();
const {data} = await axios.get(`/api/products/${id}`)
dispatch({
type: PRODUCT_DETAILS_SUCCESS,
payload: data
})
} catch (error) {
dispatch({
type: PRODUCT_DETAILS_FAIL,
payload: error.response && error.response.data.message
? error.response.data.message
: error.message,
})
}
}
productReducer.js:
export const productDetailsReducer = (state={product:{reviews:[]}},action) => {
switch(action.type){
case PRODUCT_DETAILS_REQUEST:
return {loading:true, ...state}
case PRODUCT_DETAILS_SUCCESS:
return {loading:false, product:action.payload}
case PRODUCT_DETAILS_FAIL:
return {loading:false, error: action.payload}
default:
return state
}
}
store.js:
import { legacy_createStore as createStore, combineReducers, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import {productListReducer,productDetailsReducer} from './reducers/productReducers'
const reducer = combineReducers({
productList: productListReducer,
productDetails: productDetailsReducer,
})
const initialState = {}
const middleware = [thunk]
const store = createStore(reducer, initialState,
composeWithDevTools(applyMiddleware(...middleware)))
export default store
export const listProductDetails = (id) => async(dispatch) => {
try {
dispatch({type: PRODUCT_DETAILS_REQUEST})
const { id } = useParams();
[...]
You are passing id as argument of listProductDetails then you are redefining it inside the function.
Move const { id } = useParams(); into ProductScreen and pass it as argument to function instead of using match.
Also listProductDetails returns an async function that takes dispatch as argument. So don't call dispatch(listProductDetails(id)) but instead call listProductDetails(id)(dispatch).
Also calling dispatch within the api is not a good idea. You generally want action function to return something to be dispatched within a React Component.
function ProductScreen() {
const dispatch = useDispatch();
const { id } = useParams();
const productDetails = useSelector((state) => state.productDetails);
const { loading, error, product } = productDetails;
useEffect(() => {
const fetchData = async (id) => {
dispatch({ type: PRODUCT_DETAILS_REQUEST });
dispatch(await listProductDetails(id));
};
fetchData(id);
}, [dispatch, id]);
return <div>APP</div>;
}
In ProductActions.js
export const listProductDetails = async (id) => {
try {
const { data } = await axios.get(`/api/products/${id}`);
return {
type: PRODUCT_DETAILS_SUCCESS,
payload: data,
};
} catch (error) {
return {
type: PRODUCT_DETAILS_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
};
}
};
I just learned how react-redux works.
I created a backend with express js and used axios in the fronted(authentication). After I login, it just gives me a success status.but I can't understand why after success login the state still like initialState in reducer
login.js
import React,{ useState} from 'react'
import { connect, useDispatch } from 'react-redux'
import {login} from '../../actions/authentication'
import './auth.css'
import LoginForm from './LoginForm'
import {Link} from 'react-router-dom'
const Login = ({history, login}) => {
const dispatch = useDispatch();
const [formData, setFormData] = useState({
email: "",
password:""
});
const hundleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value })
}
const hundleSubmit = (e) => {
e.preventDefault();
dispatch(login(formData));
history.push("/");
}
return(
<div>
<div className="forms">
<h2>Login</h2>
<LoginForm email = {formData.email}
password = {formData.password}
hundleSubmit = {hundleSubmit}
hundleChange = {hundleChange}/>
</div>
<p>Do you not have account</p>
<Link to="/register">Sign Up</Link>
</div>
)
}
const mapStateToProps = state => (
{
auth : state.auth
}
)
export default connect (mapStateToProps, {login})(Login);
authentication.js
import axios from 'axios'
import { AUTH_FAILURE, LOGIN_USER_SUCCESS } from './types'
//login user
export const login = (formData) => async (dispatch) =>{
//formData ={email, password}
try {
const res = await axios.post("/api/auth/login", formData)
dispatch({
type: LOGIN_USER_SUCCESS,
payload: res.data
});
console.log("here data", dispatch.payload)
} catch (error) {
console.dir(error);
const response = error.response.data;
if(Array.isArray(response)){
response.forEach((err) =>
{
alert(err.msg);
});
}
dispatch({
type: AUTH_FAILURE
});
}
}
authReducer.js
import {LOGIN_USER_SUCCESS} from '../actions'
const initialState = {
token: null,
user:null,
isLoading: false,
isAuth: false
};
export default (state = initialState, {type, payload}) => {
switch(type) {
case LOGIN_USER_SUCCESS:
return {...state,
user: payload.user,
token: payload.token,
isLoading: false,
isAuth: true
};
default:
return state;
}
};
redux_devtools1
redux_devtools2
I found the solution,the problem was with the import
import {LOGIN_USER_SUCCESS} from '../actions/types'
import axios from 'axios'
import {LOGIN_USER_SUCCESS} from '../actions/types'
//login user
export const login = (formData) => async (dispatch) =>{
//formData ={email, password}
try {
const res = await axios.post("/api/auth/login", formData)
dispatch({
type: LOGIN_USER_SUCCESS,
payload: res.data
});
console.log("here data", dispatch.payload)
} catch (error) {
console.dir(error);
const response = error.response.data;
if(Array.isArray(response)){
response.forEach((err) =>
{
alert(err.msg);
});
}
dispatch({
type: AUTH_FAILURE
});
}
}
I have an actions file called menu that uses axios to get JSON data from a backend API. I then have reducers which are called in a MainMenu.js file which gets the data. All of the data is shown in the Redux devtools. However I am only able to access the data I have in intitialState. There should be an array of three items but it only shows the first one in intitialState. The data from the reducers does not show up when I try to console.log it. So obviously I would not be able to render it to the DOM.
actions/menu.js
import { ADD_PRODUCT, GET_PRODUCTS, GET_PRODUCT } from './types';
import axios from 'axios';
export const getProducts = () => (dispatch) => {
axios
.get('http://localhost:8080/menu')
.then((response) => {
// console.log(response);
const data = response.data;
dispatch({
type: GET_PRODUCTS,
payload: { data },
});
})
.catch((err) => {
console.log(err);
});
};
export const getProduct = (product) => (dispatch) => {
axios
.get(`http://localhost:8080/menu/${product}`)
.then((response) => {
// console.log(response);
const data = response.data;
dispatch({
type: GET_PRODUCT,
payload: { data },
});
})
.catch((err) => {
console.log(err);
});
};
reducers/index.js
import { combineReducers } from 'redux';
import menu from './menu';
export default combineReducers({ menu });
reducers/menu.js
import { GET_PRODUCTS, GET_PRODUCT } from '../actions/types';
const intitialState = [
{
test: 'Test',
},
];
export default function (state = intitialState, action) {
const { type, payload } = action;
switch (type) {
case GET_PRODUCTS:
return [...state, payload];
case GET_PRODUCT:
return [...state, payload];
default:
return [...state];
}
}
components/MainMenu.js
import React, { Fragment, useEffect } from 'react';
import { connect } from 'react-redux';
import { getProducts, getProduct } from '../actions/menu';
const MainMenu = ({ getProducts, getProduct, menu }) => {
useEffect(() => {
getProducts();
getProduct('b4bc2e28-21a3-47ea-ba3b-6bad40b35504');
console.log(menu);
}, []);
return <Fragment></Fragment>;
};
const mapStateToProps = (state) => ({
menu: state,
});
export default connect(mapStateToProps, { getProducts, getProduct })(MainMenu);
I created a working solution using the ternary operator. First a check is made to see if all of the elements in the array have loaded. If they have not all loaded then a data not loaded div is displayed. Otherwise the data is rendered to the DOM.
import React, { Fragment, useEffect } from 'react';
import { connect } from 'react-redux';
import { getProducts, getProduct } from '../actions/menu';
const MainMenu = ({ getProducts, getProduct, menu }) => {
useEffect(() => {
getProducts();
getProduct('b4bc2e28-21a3-47ea-ba3b-6bad40b35504');
}, []);
if (menu.length <= 2) {
console.log('Data Not Loaded');
} else {
console.log('Data', menu[2].data.name);
}
return (
<Fragment>
<div>{menu.length <= 2 ? <div>Data not loaded</div> : <div>{menu[2].data.name}</div>}</div>
<div>
{menu.length <= 2 ? (
<div>Data not loaded</div>
) : (
<div>
{menu[1].data.map((food) => (
<div>{food.name}</div>
))}
</div>
)}
</div>
</Fragment>
);
};
const mapStateToProps = (state) => ({
menu: state.menu,
});
export default connect(mapStateToProps, { getProducts, getProduct })(MainMenu);
Ive been trying to do this with react hooks and the useSelector/useDispatch. What happens is, I am able to see the data and state change in the Redux DevTools however, when logging to the console, I either get an empty array or undefined. I am also not able to render the data to the screen expectedly.
Posts Component
import React, {useState, useEffect} from 'react'
import PropTypes from 'prop-types'
import {useSelector, useDispatch} from 'react-redux'
import {getPosts} from '../actions/postActions'
const Posts = props =>{
const dispatch = useDispatch();
const postData = useSelector(state=> state.items, []) || []; //memoization?
const [items, setItems] = useState(postData)
console.log(postData);
useEffect(() => {
dispatch(getPosts());
}, []);
return(
<h1>{postData[0]}</h1>
)
}
export default Posts
ACTIONS
import {GET_POSTS, NEW_POSTS} from '../actions/types'
export const getPosts =()=> dispatch =>{
//fetch
console.log('fetching')
const url = 'https://jsonplaceholder.typicode.com/posts/'
fetch(url)
.then(res => res.json())
.then(posts=> dispatch({type: GET_POSTS, payload: posts}))
}
reduxDevTools image
I think the problem is coming from this line:
const postData = useSelector(state=> state.items, []) || [];
If you want postData to initially be an array, it's best to set it as an array in your reducer.
Working example (click Posts tab to make API call):
actions/postActions.js
import api from "../utils/api";
import * as types from "../types";
export const getPosts = () => async dispatch => {
try {
dispatch({ type: types.POSTS_FETCH });
const res = await api.get("posts");
dispatch({
type: types.POSTS_SET,
payload: res.data
});
} catch (err) {
dispatch({
type: types.POSTS_FAILED_FETCH,
payload: err.toString()
});
}
};
reducers/postsReducer.js
import * as types from "../types";
const initialState = {
data: [],
error: "",
isLoading: true
};
export default (state = initialState, { type, payload }) => {
switch (type) {
case types.POSTS_FETCH:
return initialState;
case types.POSTS_SET:
return {
...state,
data: payload,
error: "",
isLoading: false
};
case types.POSTS_FAILED_FETCH:
return {
...state,
error: payload,
isLoading: false
};
default:
return state;
}
};
containers/FetchPostsHooks/index.js
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { getPosts } from "../../actions/postActions";
import Spinner from "../../components/Spinner";
import DisplayPosts from "../../components/DisplayPosts";
const Posts = () => {
const dispatch = useDispatch();
const { isLoading, data, error } = useSelector(state => state.posts, []);
useEffect(() => {
dispatch(getPosts());
}, [dispatch]);
return isLoading ? (
<Spinner />
) : error ? (
<p>{error}</p>
) : (
<DisplayPosts data={data} />
);
};
export default Posts;
Tell me please why i can't to get local data from json in axios.
db.json is at the root of the project, but in the getEvents function it throws error 404.
Help me please
operation.js
import FetchClient from 'app/utils/FetchClient';
import IdsAndByIds from 'app/utils/IdsAndByIds';
import { eventsFetch, setEvents } from './actions';
export const getEvents = () => async (dispatch) => {
try {
const { data } = await FetchClient.get('./db.json');
dispatch(setEvents(IdsAndByIds(data)));
dispatch(eventsFetch(false));
} catch (error) {
console.log(error);
}
};
FetchClient.js
import axios from 'axios';
import { URL_API } from 'app/config'; //localhost:3009
const FetchClient = () => {
const defaultOptions = {
baseURL: URL_API,
method: 'get',
headers: {
'Content-Type': 'application/json'
}
};
const instance = axios.create(defaultOptions);
return instance;
};
export default FetchClient();
actions.js
import * as types from './types';
export const eventsFetch = value => ({
type: types.FETCHING_EVENTS,
payload: value
});
export const setEvents = ({ objById, arrayIds }) => ({
type: types.SET_EVENTS,
payload: {
eventById: objById,
eventsOrder: arrayIds
}
});