Why reducer throws ReferenceError? - reactjs

This my first version, but it didn't work well with Next.js:
import { createReducer } from '../storeUtils';
import { SET_PRODUCT_DEPARTMENTS } from '../actions/productActions';
const initialState = {
productDepartments: []
};
function setProductDepartments(state, action) {
return {
...state,
productDepartments: action.payload
};
}
export default createReducer(initialState, {
[SET_PRODUCT_DEPARTMENTS]: setProductDepartments
});
In this case when I write "next build" it throws this error:
ReferenceError: Cannot access 'SET_PRODUCT_DEPARTMENTS' before initialization
But in this case everything good:
import { SET_PRODUCT_DEPARTMENTS } from '../actions/productActions';
const initialState = {
productDepartments: []
};
const productReducer = (state = initialState, action) => {
switch (action.type) {
case SET_PRODUCT_DEPARTMENTS:
return {
...state,
productDepartments: action.payload
};
default:
return state;
}
};
export default productReducer;
Tell me what was the problem between these two?

Related

TypeError: state.products.find is not a function or its return value is not iterable

import { ActionType } from "../costants/action-type";
const initialState = {
products : [],
}
export const productReducer = (state = initialState, {type,payload}) => {
console.log("DEC",payload)
console.log("state",state.products)
switch (type) {
case ActionType.SET_PRODUCTS:
return {state ,
products: [...state.products.find(product => product.API === payload.API)],
};
default:
return state;
}
}
The screenshot for my error
You should use map (returns a list) instead of find (returns a single object).
And you should assign state like {...state } to keep all current state values as well.
import { ActionType } from "../costants/action-type";
const initialState = {
products : [],
}
export const productReducer = (state = initialState, {type,payload}) => {
console.log("DEC",payload)
console.log("state",state.products)
switch (type) {
case ActionType.SET_PRODUCTS:
return {
...state,
products: [...state.products.map(product => product.API === payload.API)],
};
default:
return state;
}
}

Error when import my library on a project

I'm creating a library using create-react-library. My library uses typescript, hooks and redux.
I think that my problem is by typescript or hooks.. because I've tried different ways to export and always show same error.
./src/redux/RootReducer.tsx
Attempted import error: 'react-tree-library' does not contain a default export (imported as 'HierarchyTreeReducerState').
I've tried:
Use export const
// Export a variable
export const App = () => { ... }
// Import App in another file
import { App } from '...'
Use export default
// Export default
const App = () => { ... }
export default App
// Import App in another file
import App from "...";
// And this option
import { App } from "...";
As you can see:
const MainTree = ({
data,
portal,
branch,
...
}: MainProps) => { ... }
const mapStateToProps = createStructuredSelector({
branch: makeSelectBranchItem(),
hierarchy: makeSelectHierarchyItem(),
});
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
...
dispatch,
};
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
export default compose(withConnect)(MainTree);
Reducers:
const HierarchyTreeReducerState = (state = initialState, action: any) => {
switch (action.type) {
case HierarchyTreeConstants.SET_SELECTED: {
return Object.assign({}, state, {
selected: action.payload,
});
}
case HierarchyTreeConstants.SET_DMA: {
return Object.assign({}, state, {
selectedDma: action.payload,
});
}
case HierarchyTreeConstants.SET_HIDDEN_BRANCHS: {
return Object.assign({}, state, {
hiddenBranchs: action.payload,
});
}
default:
return state;
}
};
export default HierarchyTreeReducerState;
const TreeReducerState = (state = initialState, action: any) => {
switch (action.type) {
case TreeConstants.SET_NUMBRANCHS: {
return Object.assign({}, state, {
numBranchs: action.payload
});
}
case TreeConstants.SET_BRANCH: {
return Object.assign({}, state, {
branchs: action.payload,
});
}
default:
return state;
}
};
export default TreeReducerState;
index.ts of Library:
export const TreeGoaiguaLibrary = ({
portal,
removeBranchWithChildren,
data,
}: Props) => {
return (
<Main
removeBranchWithChildren={removeBranchWithChildren}
data={data}
portal={portal}
/>
);
};
export { TreeGoaiguaLibrary , TreeReducer, HierarchyTreeReducer };
And when I do yarn link to library, I import in RootReducer of other project to use my library I do this:
import { combineReducers } from "redux";
import TreeReducerState from "react-goaigua-tree-library";
import HierarchyTreeReducerState from "react-goaigua-tree-library";
const combinedReducers = combineReducers({
branch: TreeReducerState,
hierarchy: HierarchyTreeReducerState,
} as any);
export const RootReducer = (state: any, action: never): any => {
return combinedReducers(state, action);
};
And show the error:
./src/redux/RootReducer.tsx
Attempted import error: 'react-tree-library' does not contain a default export (imported as 'HierarchyTreeReducerState').
I've solved ( I think )
index.ts of Library
import MainTree from "./components/main";
import HierarchyTreeReducerState from "./redux/reducers/HierarchyTreeReducer";
import TreeReducerState from "./redux/reducers/TreeReducer";
export { MainTree };
export default { TreeReducerState, HierarchyTreeReducerState };
Reducers:
export const HierarchyTreeReducerState = (state = initialState, action: any) => {
switch (action.type) {
case HierarchyTreeConstants.SET_SELECTED: {
return Object.assign({}, state, {
selected: action.payload,
});
}
case HierarchyTreeConstants.SET_DMA: {
return Object.assign({}, state, {
selectedDma: action.payload,
});
}
case HierarchyTreeConstants.SET_HIDDEN_BRANCHS: {
return Object.assign({}, state, {
hiddenBranchs: action.payload,
});
}
default:
return state;
}
};
export default HierarchyTreeReducerState;
export const TreeReducerState = (state = initialState, action: any) => {
switch (action.type) {
case TreeConstants.SET_NUMBRANCHS: {
return Object.assign({}, state, {
numBranchs: action.payload
});
}
case TreeConstants.SET_BRANCH: {
return Object.assign({}, state, {
branchs: action.payload,
});
}
default:
return state;
}
};
export default TreeReducerState;
Now show me this error:

React redux action resetting non attached state

When triggering an action updateLog, it seems it resets other state items. In my case updateLog should manipulate log and that works just fine. The thing is it also resets tasks to the default values. What am I doing wrong here?
Component:
class Generator extends Component {
render() {
return (
<div className="generator">
<Inputs />
<button onClick={this.generate.bind(this)}>Go!</button>
<Log />
</div>
);
}
generate() {
this.props.updateLog("ANYTHING!");
}
}
function mapStateToProps(state) {
return {
tasks: state.tasks
};
}
function matchDispatchToProps(dispatch){
return bindActionCreators({updateLog: updateLog}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(Generator);
Action:
export const updateLog = (message) => {
return {
type: 'LOG_UPDATED',
payload: message
}
};
Logreducer:
const initialLog = "";
export default function (state = initialLog, action) {
switch (action.type) {
case 'LOG_UPDATED':
return state + "\n" + action.payload
break;
}
return state;
}
All reducers:
const allReducers = combineReducers({
tasks: taskReducer,
log: logReducer
});
export default allReducers
taskReducer:
export default function (state = null, action) {
switch (action.type) {
case 'TASK_UPDATED':
var tasks = Object.assign({}, action.payload);
return tasks;
break;
}
// Default task properties
return {
CreateDatabaseTask: {
enabled: false,
type: "sqlite"
}
}
}
The problem lies in your task reducer. If the action type matches none of the ones defined in the switch statement, you should return the current state. Instead, you are returning the initial state.
Try changing it to return the current state instead:
const initialState = {
CreateDatabaseTask: {
enabled: false,
type: "sqlite"
}
}
export default function (state = initialState, action) {
switch (action.type) {
case 'TASK_UPDATED':
var tasks = Object.assign({}, action.payload);
return tasks;
break;
default:
return state;
}
}

"Expected the reducer to be a function." only on server

I am building an isomorphic app and I have a strange problem with my store and reducers. When I import my reducers in the client side store, it all works:
import reducers from '../Reducers';
...
let store = createStore(reducers, initial, composeEnhancers(applyMiddleware(...middleware)));
export default store;
But when I try to do the same on the server:
import reducers from '../source/js/Reducers';
I am getting error in the console
Error: Expected the reducer to be a function.
My reducers are like this:
import { INSERT_POST, INSERT_CONTENT, BUMP_PAGE, FETCH_COLLECTION } from '../Actions/Content';
const defaultState = {
currentPage: 0,
nextPage: 1,
content: [],
fetched: []
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case INSERT_POST:
return { ...state, content: [ ...state.content, action.payload ], fetched: [ ...state.fetched, action.url ] };
case INSERT_CONTENT:
const newState = {...state};
newState.content[action.payload.id].content = action.payload.data;
return newState;
case `${FETCH_COLLECTION}_SUCCESS`:
return { ...state, fetched: [ ...state.fetched, action.meta.previousAction.payload.request.url ]};
case BUMP_PAGE:
return { ...state, currentPage: state.nextPage, nextPage: ++state.nextPage };
default:
return state;
}
};
export default reducer;
...
import { START_TRANSITION, END_TRANSITION, TOGGLE_TRANSITION } from '../Actions/Transitions';
const defaultState = {
loaded: true
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case START_TRANSITION:
return { ...state, loaded: false };
case END_TRANSITION:
return { ...state, loaded: true };
case TOGGLE_TRANSITION:
return { ...state, loaded: !state.loaded };
default:
return state;
}
};
export default reducer;
And the main reducer:
import { combineReducers } from 'redux';
import Transitions from './Transitions'
import Content from './Content';
export default combineReducers({
Transitions,
Content
});
I have no idea of what to do with this. It's the first time I ever see such error. What can I do?

REACT can't do object assign in reducer

I got a problem when do objectAssign to change the state in store into a new data from server, It always get a null as the result.
i call my action in onEnter function(React-Router)
export function GET_SetupTabTitles() {
store.dispatch(getSetupTabTitles());
}
this is my action :
import {
TOGGLE_DRAWER_IN_APPBAR,
GET_SETUP_TAB_TITLES,
} from '../constants/actionTypes';
import axios from 'axios';
const ROOT_URL = 'http://localhost:8000';
export function toggleDrawerInAppBar(open){
return { type: TOGGLE_DRAWER_IN_APPBAR, openStatus: open }
}
export function getSetupTabTitles(){
return function(dispatch){
axios.get(`${ROOT_URL}/api/component/getSetupTabTitles`)
.then(response => {
dispatch({type: GET_SETUP_TAB_TITLES,
payload: response
});
});
}
}
this is my initial state on reducer :
export default {
auth: {
authenticated: (localStorage.getItem('laravel_user_token') !== null),
userinfo: {
name: null
},
error:""
},
comp: {
openDrawerStatus: false,
setupTabTitles: null,
}
};
and this is my reducer :
import {
TOGGLE_DRAWER_IN_APPBAR,
GET_SETUP_TAB_TITLES,
} from '../constants/actionTypes';
import initialState from './initialState';
import objectAssign from 'object-assign';
const compReducer = (state = initialState.comp, action) => {
switch (action.type) {
case TOGGLE_DRAWER_IN_APPBAR:
return objectAssign({}, state, {openDrawerStatus: action.openStatus});
case GET_SETUP_TAB_TITLES:
console.log(action.payload.data);
return objectAssign({}, state, {setupTabTitles: action.payload.data});
default:
return state;
}
};
export default compReducer;
when i do console.log inside
case GET_SETUP_TAB_TITLES:
it show :
Array[2]0: 0:Object 1:Object
On using JSON.stringify() it shows me [{"tabTitle":"Events"},{"tabTitle":"Tasks"}]
but my state (setupTabTitles) didn't change at all.
i do try this one :
case GET_SETUP_TAB_TITLES:
state.setupTabTitles.push(action.payload.data[0]);
return state;
it work, but i don't want to direct change the state.
You don't need to import ojectAssign from 'object-assign'; when you make use of the current ES6 syntax in your code. You only need Object.assign. Also since your action.data.payload is an array and you need to append to an array you can use the spread operator like
return {
...state,
setupTabTitles: [...state.setupTabTitles, action.payload.data]
}
Also you need to initialise you componentState to be an empty array and not null or undefined. Change that to below code
export default {
auth: {
authenticated: (localStorage.getItem('laravel_user_token') !== null),
userinfo: {
name: null
},
error:""
},
comp: {
openDrawerStatus: false,
setupTabTitles: [],
}
};
Try it like below
const compReducer = (state = initialState.comp, action) => {
switch (action.type) {
case TOGGLE_DRAWER_IN_APPBAR:
return Object.assign({}, state, {openDrawerStatus: action.openStatus});
case GET_SETUP_TAB_TITLES:
console.log(action.payload.data);
return {
...state,
setupTabTitles: [...state.setupTabTitles, ...action.payload.data]
}
default:
return state;
}
};
The syntax of objectAssign is different from what I use, you can see it here
var state = {
openDrawerStatus: false,
setupTabTitles: [],
}
var payload = [{"tabTitle":"Events"},{"tabTitle":"Tasks"}]
console.log( {
...state,
setupTabTitles: [...state.setupTabTitles, ...payload]
});
As you are already using ES6, you could just use the object spread operator and get rid of the object-assign library, it would be like this:
import {
TOGGLE_DRAWER_IN_APPBAR,
GET_SETUP_TAB_TITLES,
} from '../constants/actionTypes';
import initialState from './initialState';
const compReducer = (state = initialState.comp, action) => {
switch (action.type) {
case TOGGLE_DRAWER_IN_APPBAR:
return { ...state, openDrawerStatus: action.openStatus };
case GET_SETUP_TAB_TITLES:
return { ...state, setupTabTitles: action.payload.data };
default:
return state;
}
};
export default compReducer;
In your initial state, I would change setupTabTitle from null to an empty array []:
setupTabTitles: [],
And in your reducer, append data to this array:
const compReducer = (state = initialState.comp, action) => {
switch (action.type) {
...
case GET_SETUP_TAB_TITLES:
return {
...state,
setupTabTitles: [
...state.setupTabTitles,
...action.payload.data
]
}
...
}
};
Or if you don't want to append, just replace, I would do:
setupTabTitles: [
...action.payload.data
]

Resources