I wonder why my state todos named todo not todos in the redux dev tools ..
From where that name came ?
There is no initial state .. i wonder..
I'm following Stephen Grider udemy course but with todos instead of streams as a revision
why i have to return it by state.todo not state.todos??
My github Repo
Jsson server db.json file ( api file )
{
"todos": [
{
"title": "lorem ipsum ",
"description": "lorem ipsum",
"id": 4
}
]
}
todoReducer.js
import _ from 'lodash';
import {
CREATE_TODO,
EDIT_TODO,
FETCH_TODO,
FETCH_TODOS,
DELETE_TODO
} from '../actions/types';
export default (state = {}, action) => {
switch (action.type) {
case FETCH_TODOS:
return { ...state, ..._.mapKeys(action.payload, 'id') };
case CREATE_TODO:
case FETCH_TODO:
case EDIT_TODO:
return { ...state, [action.payload.id]: action.payload };
case DELETE_TODO:
return _.omit(state, action.payload);
default:
return state;
}
};
actions/index.js
import todos from '../apis/todos';
import history from '../history';
import {
SIGN_IN,
SIGN_OUT,
CREATE_TODO,
EDIT_TODO,
FETCH_TODO,
FETCH_TODOS,
DELETE_TODO
} from './types';
export const signIn = userId => {
return { type: SIGN_IN, payload: userId };
};
export const signOut = () => {
return { type: SIGN_OUT };
};
export const fetchTodos = () => async dispatch => {
const response = await todos.get('/todos');
dispatch({ type: FETCH_TODOS, payload: response.data });
};
export const createTodo = formValues => async dispatch => {
const response = await todos.post('/todos', formValues);
dispatch({ type: CREATE_TODO, payload: response.data });
history.push('/');
};
https://github.com/HosMercury/todos/blob/master/src/reducers/index.js here you are passing the list as todo not as todos.
Here you can check console in sandbox
https://codesandbox.io/s/github/HosMercury/todos
Related
After introducing Redux to my React Native Expo app, whenever I try to interact with the database my app stops working.
actions.js:
export const SET_SELECTED_PLAYERS = "SET_SELECTED_PLAYERS"
export const SET_PLAYERS = "SET_PLAYERS"
export const SET_SELECTED_COURSE = "SET_SELECTED_COURSE"
export const SET_COURSES = "SET_COURSES"
//Player actions
export const setPlayers = (players) => (
{ type: SET_PLAYERS, payload: players, }
)
export const setSelectedPlayers = (players) => (
({ type: SET_SELECTED_PLAYERS, payload: players, })
)
export const setSelectedCourse = (course) =>
({ type: SET_SELECTED_COURSE, payload: course, })
export const setCourses = (courses) =>
({ type: SET_COURSES, payload: courses, })
reducers.js:
import { SET_PLAYERS, SET_SELECTED_PLAYERS, SET_SELECTED_COURSE, SET_COURSES } from "./actions"
const initialState = {
players: [],
selectedPlayers: [],
courses: [],
selectedCourse: null,
round: {}
}
export const playerReducer = (state = initialState, action) => {
switch (action.type) {
case SET_PLAYERS:
return { ...state, players: action.payload }
case SET_SELECTED_PLAYERS:
return { ...state, selectedPlayers: action.payload }
default:
return state
}
}
export const courseReducer = (state = initialState, action) => {
switch (action.type) {
case SET_SELECTED_COURSE:
return { ...state, selectedCourse: action.payload }
case SET_COURSES:
return { ...state, courses: action.payload }
default:
return state
}
}
store.js:
import { createStore, combineReducers, applyMiddleware } from "redux";
import { courseReducer, playerReducer } from "./reducers";
const rootReducer = combineReducers({ playerReducer, courseReducer })
export const Store = createStore(rootReducer)
SQLite used in component :
const dispatch = useDispatch()
const db = SQLite.openDatabase("players.db")
useEffect(() => {
db.transaction(tx => {
tx.executeSql("SELECT * FROM Player", [], (trans, result) => {
dispatch(setPlayers(result.rows._array))
})
})
}, [])
Table for Player exists and app worked before I introduced Redux. It interacts with Firebase and when fetching data from cloud Redux has no problems. What problems could it have with SQLite?
Use sqlite query in redux action
export const getUsers = () => {
try {
return async dispatch => {
const result = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
const json = await result.json();
if (json) {
dispatch({
type: GET_USERS,
payload: json
})
} else {
console.log('fetch user api error');
}
}
} catch (error) {
console.log('action error');
}
}
I'm having a challenge with redux as I keep getting this error: TypeError: undefined is not an object (evaluating '_useSelector.attendance'). Everything seems to be working fine but I just done understand why it keeps coming back to this even when it seems the code is okay to my knowledge
Reducers.js
import { GET_ATTENDANCE, ADD_TO_ATTENDANCE_LIST } from "./actions";
const initialState = () => ({
attendance: [],
attendancebook: [],
});
function attendanceReducer(state = initialState, action) {
switch (action.type) {
case GET_ATTENDANCE:
return { ...state, attendance: action.payload };
case ADD_TO_ATTENDANCE_LIST:
return {
...state,
attendancebook: [...state.attendancebook, action.payload],
};
default:
return state;
}
}
export default attendanceReducer;
AttendanceScreen.js
function AttendanceScreen({ route }) {
const navigation = useNavigation();
const listing = route.params;
const dispatch = useDispatch();
const { attendance, attendancebook } = useSelector(
(state) => state.attendanceReducer
);
const getAttendance = () => {
try {
dispatch({
type: GET_ATTENDANCE,
payload: attendancelist,
});
} catch (error) {
console.log(error);
}
};
const fetchAttendance = () => dispatch(getAttendance());
const addToAttendanceList = (data) => dispatch(addAttendance(data));
useEffect(() => {
fetchAttendance();
}, []);
store.js
import attendanceReducer from "./reducers";
const persistConfig = {
key: "root",
storage: AsyncStorage,
whitelist: ["attendancebook"],
};
const rootReducer = combineReducers({
attendanceReducer: persistReducer(persistConfig, attendanceReducer),
});
export const store = createStore(rootReducer, applyMiddleware(thunk));
export const persistor = persistStore(store);
actions.js
export const GET_ATTENDANCE = "GET_ATTENDANCE";
export const ADD_TO_ATTENDANCE_LIST = "ADD_TO_ATTENDANCE_LIST";
export const addAttendance = (data) => (dispatch) => {
dispatch({
type: ADD_TO_ATTENDANCE_LIST,
payload: data,
});
};
Please any help will be appreciated.
I have the following initialState For React Redux:
const inistialStateRedux = {
configuredFilters: {
data: {
countries: [],
divisions: [],
companies: [],
locations: [],
fields: [],
search: '',
},
},
};
Now I want to create a RESET reducer.
It looks like that:
export const createReducer = (initialState, handlers) => (
state = initialState,
action
) => {
if (action.type in handlers) {
return handlers[action.type](state, action);
}
return state;
};
export const multiUse = (reducer, name = '') => (state = null, action) => {
if (action.name !== name) return state;
return reducer(state, action);
};
import {
createReducer
} from '../helper';
import * as Action from './actions';
import inistialStateRedux from '../inistialStateRedux';
export default createReducer({
data: {},
}, {
[Action.RESET_CONFIGURED_FILTERS]: (state) => ({
...state,
data: {
...inistialStateRedux.configuredFilters.data,
},
}),
});
But Redux Devtools shows, that the states are equal. What am I doing wrong ?
In the Actions you can use a dispatcher to reset the Form.
Like this:
import axios from 'axios';
import { ADD} from '../modelType';
import { reset } from 'redux-form';
export const add= formValues => async dispatch => {
const res = await axios.post('/api/model/', { ...formValues });
dispatch({
type: ADD,
payload: res.data
});
dispatch(reset('yourUniqueFormName'));
};
In my web app, I want to fetch urls from an API. Also, I want to fetch categories for these items.
index.js:
componentDidMount () {
this.props.fetchUrls();
this.props.fetchCategories();
}
Im fetching the urls first like that:
export const fetchUrlsSuccess = urls => ({
type: FETCH_URLS_SUCCESS,
payload: { urls }
});
export const fetchUrls = () => dispatch => {
dispatch(fetchUrlsBegin());
return fetch(`${api}/urls`)
.then(handleErrors)
.then(res => res.json())
.then(json => {
dispatch(fetchUrlsSuccess(json));
return json.urls;
})
.catch(error => dispatch(fetchUrlsFailure(error)));
};
fetching categories:
export const fetchCategoriesSuccess = categories => ({
type: FETCH_CATEGORIES_SUCCESS,
payload: { categories }
});
export const fetchCategoriesFailure = error => ({
type: FETCH_CATEGORIES_FAILURE,
payload: { error }
});
export function fetchCategories() {
return dispatch => {
dispatch(fetchCategoriesBegin());
return fetch(`${api}/categories`)
.then(handleErrors)
.then(res => res.json())
.then(json => {
dispatch(fetchCategoriesSuccess(json));
return json.categories;
})
.catch(error => dispatch(fetchCategoriesFailure(error)));
};
}
url reducer:
import {
FETCH_URLS_BEGIN,
FETCH_URLS_SUCCESS,
FETCH_URLS_FAILURE
} from "../actions/types";
export default function urlReducer(state = [], action) {
switch (action.type) {
case FETCH_URLS_BEGIN:
console.log("url fetch begin", state);
return {
...state,
loading: true,
error: null
};
case FETCH_URLS_SUCCESS:
console.log("url fetch success", state);
return {
...state,
loading: false,
items: action.payload.urls
};
case FETCH_URLS_FAILURE:
console.log("url fetch error", state);
return {
...state,
loading: false,
error: action.payload.error,
items: []
};
default:
return state;
}
}
categories reducer:
import {
FETCH_CATEGORIES_BEGIN,
FETCH_CATEGORIES_SUCCESS,
FETCH_CATEGORIES_FAILURE
} from "../actions/types";
export default function categoriesReducer(state = [], action) {
switch (action.type) {
case FETCH_CATEGORIES_BEGIN:
console.log("categories fetch begin", state);
return {
...state,
loading: true,
error: null
};
case FETCH_CATEGORIES_SUCCESS:
console.log("categories fetch success", state);
return {
...state,
loading: false,
items: action.payload.categories
};
case FETCH_CATEGORIES_FAILURE:
console.log("categories fetch fail", state);
return {
...state,
loading: false,
error: action.payload.error,
items: []
};
default:
return state;
}
}
combining reducers in index of reducers:
import { combineReducers } from "redux";
import urlReducer from "./urlReducer";
import categoriesReducer from "./categoriesReducer";
import modalReducer from "./modalReducer";
export default combineReducers({
urls: urlReducer,
modal: modalReducer,
categories: categoriesReducer
});
create store :
import { createStore, applyMiddleware, compose } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import thunk from "redux-thunk";
import storage from "redux-persist/lib/storage";
import rootReducer from "../reducers";
const persistConfig = {
key: "root",
storage
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const middleware = [thunk];
let store = createStore(
persistedReducer,
compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
let persistor = persistStore(store);
export { store, persistor };
For the categories, I do the same. Then I combine both reducers.
What happens is that the state.urls. Items get overwritten and state.categories.items holds state instead. I don't understand why.
output of the redux dev-tool after the second fetch:
I'm pretty new to redux and don't understand the state management...
In my store.js i have the following code:
import { createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk'
const reducer = (state, action) => {
console.log(action.type)
if (action.type === 'LOAD_USERS') {
return {
...state,
users: action.users['users']
}
} else if (action.type === 'LOAD_CHATROOMS') {
return {
...state,
chatRooms: action.chatRooms['chatRooms']
}
}
return state;
}
export default createStore(reducer, {users:[], chatRooms:[]}, applyMiddleware(thunk));
the code inside the action.type === 'LOAD_CHATROOMS' is never accessed for some reason, this is the action file where i set the action type for the reducer:
import axios from 'axios'
axios.defaults.withCredentials = true
const loadUsers = () => {
return dispatch => {
return axios.get('http://localhost:3000/session/new.json')
.then(response => {
dispatch({
type: 'LOAD_USERS',
users: response.data
});
});
};
};
const logIn = user => {
return axios.post('http://localhost:3000/session', {
user_id: user.id
})
.then(response => {
//TODO do something more relevant
console.log('loged in');
});
};
const loadChatRooms = () => {
return dispatch => {
return axios.get('http://localhost:3000/session/new.json')
.then(response => {
dispatch({
type: 'LOAD_CHATROOMS',
chatRooms: response.data
});
});
};
};
const enterChatRoom = chatrom => {
};
export { loadUsers, logIn, enterChatRoom, loadChatRooms};
The 'Load methods' get the data that i use to populate both components (one for users list and the other one for chatrooms list ), both components are called at the same level in the app.js file.
Basically the output that i'm getting is the first component (users) as expected with the correct list, and the chatrooms component is also rendered but the data is not loaded (since it's corresponding reducer block is not accessed).
Thanks a lot for reading :)