Here's the error that the response looks like an empty array not a number "the length"
I want to display collection length from mongodb in react with redux.
Here's my code:
Action:
carActions.js
export const howMany = () => async (dispatch) => {
try {
dispatch({ type: CAR_NUMBER_REQUEST })
const { data } = await axios.get('/api/cars')
dispatch({ type: CAR_NUMBER_SUCCESS, data })
} catch (error) {
dispatch({
type: CAR_NUMBER_FAIL, payload: error.message})
}
}
Reducer:
carReducer.js
export const carNumberReducer = (state = { cars: [] }, action) => {
switch (action.type) {
case CAR_NUMBER_REQUEST:
return { loading: true, cars: [] }
case CAR_NUMBER_SUCCESS:
return { loading: false, success: true, cars: action.payload }
case CAR_NUMBER_FAIL:
return { loading: false, error: action.payload }
default:
return state
}
}
Here where it would be displayed:
carScreen.js
const dispatch = useDispatch()
const carNumber = useSelector(state => state.carNumber)
const { cars } = carNumber
useEffect(() => {
dispatch(howMany());
}, [dispatch])
return (
<div>
{cars.map((cars) => (
<p key={cars._id}>{cars}</p>
))}
</div>)}
Related
i made a custom hook for fetching data the problem is when i use <React.StrictMode> the fetch singal for aborting gets fire but some how it works if i remove strict mode
this is the fetch hook
import { useEffect, useReducer } from 'react';
import { ApiResponse } from '../interfaces/ApiResponse';
const initialState: ApiResponse = {
loading: false,
data: null,
error: null,
};
type Action =
| { type: 'start' }
| { type: 'error'; payload: Error }
| { type: 'success'; payload: JSON };
const reducer = (state: ApiResponse, action: Action) => {
switch (action.type) {
case 'start':
return {
loading: true,
data: null,
error: null,
};
case 'success':
return {
loading: false,
data: action.payload,
error: null,
};
case 'error':
return {
loading: false,
data: null,
error: action.payload,
};
default:
return state;
}
};
export const useFetch = (url: string): ApiResponse => {
const [response, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
const controller: AbortController = new AbortController();
const signal: AbortSignal = controller.signal;
const fetchData = async () => {
dispatch({ type: 'start' });
try {
const response: Response = await fetch(url, { signal: signal });
if (response.ok) {
const json = await response.json();
dispatch({
type: 'success',
payload: json,
});
} else {
dispatch({
type: 'error',
payload: new Error(response.statusText),
});
}
} catch (error: any) {
dispatch({
type: 'error',
payload: new Error(error),
});
}
};
fetchData();
return () => {
controller.abort();
};
}, [url]);
return response;
};
when i call this hook in one of my components like this:
const Grid = () => {
const response = useFetch(`${BASE_API_URL}/games`);
useEffect(() => {
console.log(response);
}, [response]);
return (
<div className='grid__wrapper'>
<div className='grid__content'>
{response.loading && <h4>Loading...</h4>}
<h4>helo</h4>
</div>
</div>
);
};
export default Grid;
the response.loading is never set to true and i can see an abort error in the logs but if i remove strict mode it works fine
could you please help with setting state in useContext ?
I am trying to send video variable through useEffect to setMediaContent to update mediaContext.media object. My goal is to have several media(video,images,posters) objects in media object, e.g.
https://codesandbox.io/s/friendly-sunset-o67nvj?file=/src/context.js
Thanks in advance
Try using a reducer:
import { createContext, useReducer } from "react";
// default state
const contextDefaultValues = {
video: { url: "", title: "", shown: false },
openVideo: () => {},
closeVideo: () => {},
mediaContent: { media: {}, title: "most" },
setMediaContent: () => {},
};
const MainReducer = (state = contextDefaultValues, action) => {
const { type, payload } = action;
switch (type) {
case "setMediaContent": {
const { media, title } = payload;
return { ...state, media: { ...state.media, ...media }, title: title };
}
case "closeVideo": {
return { ...state, shown: false };
}
case "openVideo": {
const { url, title } = payload;
return { ...state, url, title, shown: true };
}
default: {
throw new Error(`Unhandled action type: ${type}`);
}
}
};
export const MainContext = createContext(contextDefaultValues);
// provider recuder
const MainProvider = ({ children }) => {
const [state, dispatch] = useReducer(MainReducer, contextDefaultValues);
const openVideo = (url, title) => {
dispatch({ type: "openVideo", payload: { url, title, shown: true } });
};
const closeVideo = () => {
dispatch({ type: "closeVideo", payload: { shown: false } });
};
const setMediaContent = (media, title) => {
dispatch({ type: "setMediaContent", payload: { media, title } });
};
return (
<MainContext.Provider
value={{ ...state, setMediaContent, closeVideo, openVideo }}
>
{children}
</MainContext.Provider>
);
};
export default MainProvider;
Based on the provided sandbox, You have the render of the provider wrapped in the setMediaContent function.
Look at the { and } at line 36 and 58.
Code screenshot with misplaced brackets
Here is the list Orders file. this is the code i have created so far But when i try to map throught the orders i am reveining that error and i dont know why. When i use Postman to try and get the orders, it works pefectly fine which means im either missing a code or got an error somewhere within these codes. Does anyone have an idea or could see where the porbl;em is ? So the error i am getting is as follow
'TypeError: Cannot read property 'map' of undefined'
const { orders, loading, error } = useSelector(state => state.personalUserOrders)
const dispatch = useDispatch()
useEffect(() => {
dispatch(personalORders())
}, [ dispatch])
return (
<div>
<table className='tables'>
<thead>
<tr>
<th>Id</th>
<th>Aount</th>
</tr>
</thead>
<tbody>
{ orders.map((order) => (
<tr key={order._id}>
<td>{order._id}</td>
<td>{order.sumPrice}</td>
</tr>
))
}
</tbody>
</table>
</div>
)
}
export default OrdersList
OrdersActions file
import axios from 'axios'
import {
REQUEST_CREATE_ORDER, SUCCES_CREATE_ORDER, FAIL_CREATE_ORDER, CLEAR_ERRORS,
REQUEST_PERSONAL_ORDER, SUCCESS_PERSONAL_ORDER,FAIL_PERSONAL_ORDER
} from '../constants/orderConstant'
export const createOrders = (orders) => async (dispatch, getState) => {
try {
dispatch({
type: REQUEST_CREATE_ORDER
})
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const { data } = await axios.post(`/api/orders/newOrder`, orders, config)
console.log('Datttttta',{data})
dispatch({
type: SUCCES_CREATE_ORDER,
payload: data
})
} catch (error) {
dispatch({
type: FAIL_CREATE_ORDER,
payload: error.response.data.message
})
}
}
export const personalORders = () => async (dispatch) => {
dispatch({
type:REQUEST_PERSONAL_ORDER
})
try {
const { data } = await axios.get('/api/orders/personalOrders')
dispatch({
type: SUCCESS_PERSONAL_ORDER,
payload: data
})
} catch (error) {
dispatch({
type: FAIL_PERSONAL_ORDER,
payload: error.response.data.message
})
}
}
export const clearError=()=> async (dispatch)=>{
dispatch({
type: CLEAR_ERRORS
})
}
Orders Reducer File
import {
REQUEST_CREATE_ORDER,
SUCCES_CREATE_ORDER,
FAIL_CREATE_ORDER,
CLEAR_ERRORS,
REQUEST_PERSONAL_ORDER,
SUCCESS_PERSONAL_ORDER,
FAIL_PERSONAL_ORDER
} from '../constants/orderConstant'
export const createNewOrderReducter = (state = {}, action) => {
switch (action.type) {
case REQUEST_CREATE_ORDER:
return {
...state,
loading: true
}
case SUCCES_CREATE_ORDER:
return {
loading: false,
orders: action.payload
}
case FAIL_CREATE_ORDER:
return {
loading: false,
error: action.payload
}
case CLEAR_ERRORS:
return {
...state,
error: null
}
default:
return state
}
}
export const personalOrdersReducer = (state = { orders: [] }, action) => {
switch (action.type) {
case REQUEST_PERSONAL_ORDER:
return {
loading: true
}
case SUCCESS_PERSONAL_ORDER:
return {
loading: false,
orders: action.payload
}
case FAIL_PERSONAL_ORDER:
return {
loading: false,
error: action.payload
}
case CLEAR_ERRORS:
return {
...state,
error: null
}
default:
return state
}
}
You try to get personalUserOrders from store, however i can see just orders in your reducer.
Also you try to destruct full state object, from state.personalUserOrders
Try to use this
const { orders, loading, error } = useSelector(state => state)
I'm struggling with react-redux variable for hours...hope someone can help.
The conditional returns to me that the variable order.name is not defined, although everything goes as it should in the reducer and action.
When isLoading === true, it continues rendering {order.name} and I know it is not defined at that point because it takes some time. At that time i set Loader to do it's job..
So it’s not clear to me why he continues to render even though there’s a conditional one that shouldn’t allow it... until isLoading === false.
Here is console.log of orderDetails
import { getOrderDetailsAction } from "../actions/orderAction";
const OrderScreen = ({ match }) => {
const orderId = match.params.id;
const dispatch = useDispatch();
useEffect(() => {
dispatch(getOrderDetailsAction(orderId));
}, [dispatch, orderId]);
const orderDetails = useSelector((state) => state.orderDetails);
const { order, isLoading } = orderDetails;
return isLoading ? <Loader /> : <>{order.name}</>;
};
export default OrderScreen;
Reducer
export const orderDetailsReducers = (
state = { isLoading: true, orderItems: [], shippingAddress: {} },
action
) => {
switch (action.type) {
case ORDER_DETAILS_REQUEST:
return {
...state,
isLoading: true,
};
case ORDER_DETAILS_SUCCESS:
return {
isLoading: false,
order: action.payload,
};
case ORDER_DETAILS_FAILED:
return {
isLoading: false,
error: action.payload,
};
default:
return { state };
}
};
Action
export const getOrderDetailsAction = (id) => async (dispatch, getState) => {
try {
dispatch({
type: ORDER_DETAILS_REQUEST,
});
//Getting TOKEN
const {
userLogin: { userInfo },
} = getState();
//Passing TOKEN
const config = {
headers: {
"auth-token": `${userInfo.token}`,
},
};
const { data } = await axios.get(`/api/orders/${id}`, config);
dispatch({
type: ORDER_DETAILS_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: ORDER_DETAILS_FAILED,
payload: error.response.data.msg,
});
}
};
Check redux action for how isLoading state is changed from redux dev tools
Check reducer name -> state.orderDetails (does this exists ?)
const orderDetails = useSelector((state) => state.orderDetails);
Also, we can correct this
state = { isLoading: true, orderItems: [], shippingAddress: {}, order: {} }
// return entire state and not just isLoading and order
case ORDER_DETAILS_SUCCESS:
return {
...state, <--------
isLoading: false,
order: action.payload,
};
case ORDER_DETAILS_FAILED:
return {
...state, <---------
isLoading: false,
error: action.payload,
};
Having a strange bug/issue with redux. I have a component in an app that displays data in a table. this table is used across numerous routes and i'm passing in a url for the end point.
When i click between the routes they work fine but some fields in the table have a button to open a slide out menu. when i do the redux actions is dispatched and it fires it for all routes i have been to and not the one i'm on.
Action
export const clearTableData = () => dispatch => {
dispatch({
type: TYPES.CLEAR_TABLE_DATA,
});
};
export const getTableData = (url, limit, skip, where, sort, current) => async dispatch => {
try {
dispatch({ type: TYPES.FETCH_TABLE_DATA_LOADING });
const response = await axios.post(url, {
limit,
skip,
where,
sort
});
await dispatch({
type: TYPES.FETCH_TABLE_DATA,
payload: {
url: url,
data: response.data,
limit: limit,
skip: skip,
where: where,
sort: sort,
pagination: {
total: response.data.meta.total,
current: current,
pageSizeOptions: ["10", "20", "50", "100"],
showSizeChanger: true,
showQuickJumper: true,
position: "both"
}
}
});
dispatch({ type: TYPES.FETCH_TABLE_DATA_FINISHED });
} catch (err) {
dispatch({ type: TYPES.INSERT_ERROR, payload: err.response });
}
};
Reducer
import * as TYPES from '../actions/types';
export default (state = { loading: true, data: [], pagination: [] }, action) => {
switch (action.type) {
case TYPES.FETCH_TABLE_DATA:
return { ...state, ...action.payload };
case TYPES.FETCH_TABLE_DATA_LOADING:
return { ...state, loading: true };
case TYPES.FETCH_TABLE_DATA_FINISHED:
return { ...state, loading: false };
case TYPES.CLEAR_TABLE_DATA:
return {};
default:
return state;
}
};
component
componentDidMount() {
this.fetch();
websocket(this.props.websocketRoute, this.props.websocketEvent, this.fetch);
}
fetch = () => {
// Fetch from redux store
this.props.getTableData(
this.props.apiUrl,
this.state.limit,
this.state.skip,
{ ...this.filters, ...this.props.defaultWhere },
`${this.state.sortField} ${this.state.sortOrder}`,
this.state.current)
}
const mapStateToProps = ({ tableData }) => ({
tableData,
});
const mapDispatchToProps = dispatch => (
bindActionCreators({ getTableData }, dispatch)
)
export default connect(
mapStateToProps,
mapDispatchToProps
)(SearchableTable);
Websocket
import socketIOClient from 'socket.io-client';
import sailsIOClient from 'sails.io.js';
export const websocket = (websocketRoute, websocketEvent, callback) => {
if (websocketRoute) {
let io;
if (socketIOClient.sails) {
io = socketIOClient;
} else {
io = sailsIOClient(socketIOClient);
}
io.sails.transports = ['websocket'];
io.sails.reconnection = true;
io.sails.url = process.env.REACT_APP_WEBSOCKECTS_URL
io.socket.on('connect', () => {
io.socket.get(websocketRoute, (data, jwres) => {
console.log("connect data sss", data)
console.log("connect jwres sss", jwres)
});
});
io.socket.on(websocketEvent, (data, jwres) => {
console.log("websocket", callback)
callback();
})
io.socket.on('disconnect', () => {
io.socket._raw.io._reconnection = true;
});
}
}
So for e.g if i'm on a route for cars i'll pass in api/cars as url, and for trucks api/trucks. if i've been to both these pages they get fired.
should i be doing something to unmount and reset state to blank?
edit to add render
render() {
const { filters, columns, expandedRowRender, rowClassName, style } = this.props;
return (
<Table
bordered
columns={columns}
rowKey={record => record.id}
dataSource={this.props.tableData.data.items}
pagination={this.props.tableData.pagination}
loading={this.props.tableData.loading}
onChange={this.handleTableChange}
expandedRowRender={expandedRowRender}
rowClassName={rowClassName} />
);
Basic idea is, define a new action type in reducer file to clear the table data, and before unmount dispatch that action.
In Component:
componentDidMount() {
this.fetch();
}
componentWillUnmount() {
this.props.clearTableData();
}
const mapDispatchToProps = dispatch => (
bindActionCreators({ getTableData, clearTableData }, dispatch)
)
Action:
export const clearTableData = () => {
return { type: TYPES.CLEAR_TABLE_DATA };
};
Reducer:
case TYPES.CLEAR_TABLE_DATA: {
// reset the table data here, and return
}