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:
Related
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?
I'm trying to use createContext with useReducer and have some trouble
I'm dispatching two actions and both actions are storing their payload at the same place in the state, not to their own.
All the help will be appreciated
Here is my store
import React, { createContext, useReducer, Dispatch } from 'react';
import { InitialStateType } from './types';
import { citiesReducer, CitiesActions } from './citiesReducer';
import { LoadingActions, loadingReducer } from './loadingReducer';
const initialState: InitialStateType = {
cities: [],
loading: false,
};
const store = createContext<{
state: InitialStateType;
dispatch: Dispatch<CitiesActions | LoadingActions>;
}>({
state: initialState,
dispatch: () => {},
});
const { Provider } = store;
const mainReducer = (
{ cities, loading }: InitialStateType,
action: LoadingActions | CitiesActions,
) => ({
cities: citiesReducer(cities, action),
loading: loadingReducer(loading, action),
});
const StateProvider = ({ children }: any): React.ReactElement => {
const [state, dispatch] = useReducer<any>(mainReducer, initialState);
return <Provider value={{ state, dispatch }}>{children}</Provider>;
};
export { store, StateProvider };
Both reducers
import { ActionTypes } from './types';
export type CitiesActions = {
type: ActionTypes.SET_CITIES_DATA;
payload: [];
};
export const citiesReducer = (state: [], action: CitiesActions) => {
switch (action.type) {
case action.type:
return (state = action.payload);
default:
return state;
}
};
import { ActionTypes } from './types';
export type LoadingActions = {
type: ActionTypes.LOADING;
payload: boolean;
};
export const loadingReducer = (state: boolean, action: LoadingActions) => {
switch (action.type) {
case action.type:
return (state = action.payload);
default:
return state;
}
};
Here I'm dispatching the actions one after another
dispatch({ type: ActionTypes.SET_CITIES_DATA, payload: result });
dispatch({ type: ActionTypes.LOADING, payload: false });
And as a result, I'm getting in my state
cities: false
loading: false
instead of
cities: [data],
loading: false
You need to specify the action when handling reducers instead of having a case like case action.type in switch statement otherwise regardess of what action you dispatch all reducers will use it and set the payload. In such a case the last actions data will be set for all states
export type CitiesActions = {
type: ActionTypes.SET_CITIES_DATA;
payload: [];
};
export const citiesReducer = (state: [], action: CitiesActions) => {
switch (action.type) {
case ActionTypes.SET_CITIES_DATA: // specify the action here
return (state = action.payload);
default:
return state;
}
};
import { ActionTypes } from './types';
export type LoadingActions = {
type: ActionTypes.LOADING;
payload: boolean;
};
export const loadingReducer = (state: boolean, action: LoadingActions) => {
switch (action.type) {
case ActionTypes.LOADING: // Specify the action here
return (state = action.payload);
default:
return state;
}
};
How do I get the state of this? I only need to put it as false and true the time I want at my components, but i`m doing something wrong, i know how do it when calling an API, but not like this.
I have this actions:
import { HIDE_MENU, ESTADO_MENU } from "./types";
export const hideMenu = dispatch => {
return dispatch({
type: HIDE_MENU
});
};
export const estadoDoMenu = open => dispatch => {
dispatch({
type: ESTADO_MENU
});
};
and this reducer:
import { HIDE_MENU, ESTADO_MENU } from "../actions/types";
const initialState = {
open: true
};
export default function(state = initialState, action) {
switch (action.type) {
case HIDE_MENU:
return {
...state,
open: false
};
case ESTADO_MENU:
console.log("chega aqui");
return {
...state
};
default:
return state;
}
}
but calling it like this:
componentDidMount() {
console.log("Estado do Menu: ", this.props.estadoDoMenu());
}
I get undefined at the console, what is wrong?
Summary
In order to learn Redux, I am incorporating some state, actions, reducers, and trying to see how they are used in React Components.
I have set up a test object...
const initialState = {
navigationCount : 0,
someNumber : 500,
someList : ['aa',22,'c5d6','45615'],
};
...and aim to:
increment the navigationCount by 1 when visiting pages
add or subtract from someNumber
push() & pop() elements from someList.
Versions
Currently using gatsby ^2.5.0, react ^16.8.6, and react-redux ^6.0.1.
Code
actions & reducers
import { combineReducers } from 'redux';
import {
PAGE_INCREMENT,
NUMBER_INCREASE,
NUMBER_DECREASE,
LIST_PUSH,
LIST_POP,
} from './actionTypes.js';
// state
const initialState = {
navigationCount : 0,
someNumber : 500,
someList : ['aa',22,'c5d6','45615'],
};
// action creators returning actions
export const pageIncrementer = navigationCount => {
return {
type: PAGE_INCREMENT,
navigationCount,
};
};
export const numberAdder = numberToAdd => {
return {
type: NUMBER_INCREASE,
numberToAdd,
};
};
export const numberMinuser = numberToMinus => {
return {
type: NUMBER_DECREASE,
numberToMinus,
};
};
export const listPusher = itemToAdd => {
return {
type: LIST_PUSH,
itemToAdd,
}
};
export const listPopper = () => {
return {
type: LIST_POP,
}
};
// reducers
const pageIncrementReducer = (state = initialState, action) => {
switch (action.type) {
case PAGE_INCREMENT:
return Object.assign({}, ...state, {
navigationCount: action.navigationCount+1
});
default:
return state.navigationCount;
}
};
const numberChanger = (state = initialState, action) => {
switch (action.type) {
case NUMBER_INCREASE:
return Object.assign({}, ...state, {
someNumber: state.someNumber+action.numberToAdd,
});
case NUMBER_DECREASE:
return Object.assign({}, ...state, {
someNumber: state.someNumber-action.numberToMinus,
});
default:
return state.someNumber;
};
};
const listChanger = (state = initialState, action) => {
switch (action.type) {
case LIST_POP:
return Object.assign({}, ...state, {
someList: state.someList.pop(),
});
case LIST_PUSH:
return Object.assign({}, ...state, {
someList: state.someList.push(action.itemToAdd),
});
default:
return state.someList;
}
}
// store
const rootReducer = combineReducers({
pageIncrementReducer,
numberChanger,
listChanger,
});
export default rootReducer;
React Component
import React from 'react';
import Layout from '../components/common/Layout.jsx';
import LandingBanner from '../components/landing/LandingBanner.jsx';
import LandingNavgrid from '../components/landing/LandingNavgrid.jsx';
import LandingApp from '../components/landing/LandingApp.jsx';
import { connect } from 'react-redux';
import {
PAGE_INCREMENT,
NUMBER_INCREASE,
NUMBER_DECREASE,
LIST_PUSH,
LIST_POP,
} from '../state/actionTypes';
class LandingPage extends React.Component {
constructor(props){
super(props);
this.state = {
appliedNum: 2000,
};
}
componentDidMount(){
// this.props.pageIncrement(); // => numberChanger returned undefined
// this.props.numberIncrease(4444); // => pageIncrementReducer returned undefined
// this.props.numberDecrease(4444); // => pageIncrementReducer returned undefined
// this.props.listPush(4444); // => pageIncrementReducer returned undefined
this.props.listPop();
}
render(){
return (
<Layout>
<LandingBanner/>
<LandingNavgrid/>
<LandingApp/>
</Layout>
)
}
}
const filterNumbers = (list=[]) => {
console.log('filterNumbers list: ', list);
return list.filter(listElement => !!Number(listElement));
};
const mapStateToProps = (state, ownProps) => {
return {
someNumber: state.someNumber,
someList: filterNumbers(state.someList),
navigationCount: state.navigationCount,
};
};
const mapDispatchToProps = (dispatch) => {
return {
pageIncrement: () => dispatch({ type: PAGE_INCREMENT }),
numberIncrease: () => dispatch({ type: NUMBER_INCREASE }),
numberDecrease: () => dispatch({ type: NUMBER_DECREASE }),
listPush: () => dispatch({ type: LIST_PUSH }),
listPop: () => dispatch({ type: LIST_POP }),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(LandingPage);
Errors
redux.js:449 Uncaught Error: Given action "LIST_POP", reducer
"pageIncrementReducer" returned undefined. To ignore an action, you
must explicitly return the previous state. If you want this reducer to
hold no value, you can return null instead of undefined.
first of all, you always need to return state on the default switch case.
default:
return state;
I am trying to update the initialData for my app with an API call.
I am getting the error: (0,_configureStore2.default) is not a function.
Here is my react/ redux setup,
// app.js
import { Provider } from 'react-redux'
import configureStore from './config/configureStore';
import AppNavigation from './navigation'
import { eventsFetchData } from './actions/events'
const store = configureStore();
// dispatch action to get array of events for app
store.dispatch(eventsFetchData());
export default class App extends Component {
render() {
return (
<Provider store={store}>
<AppNavigation />
</Provider>
);
}
}
I am using a thunk to get my events data:
export const eventsHasErrored = bool => ({
type: 'EVENTS_HAS_ERRORED',
hasErrored: bool
})
export const eventsIsLoading = bool => ({
type: 'EVENTS_IS_LOADING',
isLoading: bool
})
export const eventsFetchDataSuccess = events => ({
type: 'EVENTS_FETCH_DATA_SUCCESS',
events
})
export function eventsFetchData(url) {
return (dispatch) => {
dispatch(eventsIsLoading(true));
fetch(url)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
dispatch(eventsIsLoading(false));
return response;
})
.then((response) => response.json())
.then((events) => dispatch(eventsFetchDataSuccess(items)))
.catch(() => dispatch(eventsHasErrored(true)));
};
}
My reducers are:
export function eventsHasErrored(state = false, action) {
switch (action.type) {
case 'EVENTS_HAS_ERRORED':
return action.hasErrored;
default:
return state;
}
}
export function eventsIsLoading(state = false, action) {
switch (action.type) {
case 'EVENTS_IS_LOADING':
return action.isLoading;
default:
return state;
}
}
export function events(state = [], action) {
switch (action.type) {
case 'EVENTS_FETCH_DATA_SUCCESS':
return {
...state,
...action.events,
};
default:
return state;
}
}
export function calendarView(state = null, action) {
switch (action.type) {
case 'CALENDAR_VIEW':
return action.viewType;
default:
return state;
}
}
This is my store:
const initialState = {
eventsHasErrored: false,
eventsIsLoading: true,
events: [],
calendarView: 0
};
const reduxLogger = createLogger();
const store = createStore(
rootReducer,
initialState,
applyMiddleware(thunk, reduxPromise, reduxLogger)
);
export default store;
How would be best to update my initialState from an api call?
Try:
// app.js
import { Provider } from 'react-redux'
import store from './config/configureStore';
import AppNavigation from './navigation'
import { eventsFetchData } from './actions/events'
// dispatch action to get array of events for app
store.dispatch(eventsFetchData());
export default class App extends Component {
render() {
return (
<Provider store={store}>
<AppNavigation />
</Provider>
);
}
}
That's because I see that you return already created store and this would explain the error message:
const store = createStore(
rootReducer,
initialState,
applyMiddleware(thunk, reduxPromise, reduxLogger)
);
export default store;