I have the following JS code from a tutorial:
if (process.env.NODE_ENV === 'production') {
module.exports = require('./configureStore.prod');
} else {
module.exports = require('./configureStore.dev');
}
The configureStore.*.ts files both have a default export:
export default function configureStore(initialState?: State) {
// ...
}
I want to translate the conditional export in the former code snippet into TypeScript. If I just leave the code as is, I get a compile-time error:
error TS2306: File 'configureStore.ts' is not a module.
After some trial and error I could get the following to compile:
import {Store} from "redux";
import {State} from "../reducers";
let configureStore: (state?: State) => Store<State>;
if (process.env.NODE_ENV === "production") {
configureStore = require("./configureStore.prod");
} else {
configureStore = require("./configureStore.dev");
}
export default configureStore;
I tried using it like this:
import configureStore from "./store/configureStore";
const store = configureStore();
But I got this error message at runtime:
TypeError: configureStore_1.default is not a function
How can I successfully translate the original code into TypeScript?
if (process.env.NODE_ENV === "production") {
configureStore = require("./configureStore.prod").default;
} else {
configureStore = require("./configureStore.dev").default;
}
Related
I am using NextJs with React-Quill ı am getting error.
Error : - error - unhandledRejection: ReferenceError: document is not defined
at Object. \node_modules\quill\dist\quill.js:7661:12)
When I did research they said to use dynamic import for this problem. But dynamic also not working.
dynamic import not working, is there any other solution ?
I also Try _app js folder conditional render (typeof window !== "undefined") not work.
My Code Here >
import React from 'react';
import { getSession } from 'next-auth/react';
import dynamic from 'next/dynamic';
const ReactQuill = dynamic(import('react-quill'), {
ssr: false,
loading: () => <p>Loading ...</p>,
});
function EditService() {
return <ReactQuill />;
}
export async function getServerSideProps(context) {
const session = await getSession({ req: context.req });
if (!session) {
return {
redirect: {
destination: '/',
permanent: false,
},
};
}
return {
props: {},
};
}
export default EditService;
Facing problem with importing and exporting files. This was working with react-native 0.51.0
But not in react-native: 0.56
"babel-eslint": "7.2.3",
"babel-plugin-transform-remove-console": "6.9.0",
"babel-preset-react-native": "^5",
Is it a problem with module.exports and export default or with babel version?
Getting error saying that
Cannot read property 'default' of undefined
Object.get [as API]
repolib/index.js
import * as components from './components';
import * as utils from './utils';
var Utils = {
Logger: utils.Logger,
Toast: utils.Toast
}
var Components = {
Button: components.Button
}
module.exports = {
Utils,
Components,
}
Utils/Toast.js
var Toast = require('../repolib').Utils.Toast;
export default {
...(Toast)
}
API/loginAPI.js
import Toast from '../Utils/Toast';
export default {
login: () => {...}
}
API/index.js
import loginAPI from './loginAPI';
export default {
loginAPI
}
common/index.js
export { default as API } from '../API';
I am trying to use redux-saga to call my API and passing it a parameter. I am using redux-logger and console.log() to debug. But it seems that my saga doesn't go call the API for some reason.
Here is the console log of the states... as you can see the apiMsg doesnt change, however I have it change for each action.
I think I am going wrong somewhere in the actions, reducer or the component. Or else I am calling the API wrong in the Saga.
This is my code
api.js
import axios from 'axios';
export function getPostApi(postId){
return axios.get(
`https://jsonplaceholder.typicode.com/posts/${postId}`
).then(
response => {
return response;
}
).catch(
err => {throw err;}
);
}
my store
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga'
import {createLogger} from 'redux-logger';
import rootReducer from '../Reducers';
export default function configureStore(initialState) {
const sagaMiddleware = createSagaMiddleware();
const logger = createLogger();
return {
...createStore(rootReducer, initialState, applyMiddleware(sagaMiddleware, logger)),
runSaga: sagaMiddleware.run
}
}
the saga
import {call, put, takeEvery} from 'redux-saga/effects';
import * as service from '../Services/api';
import * as actions from '../Actions';
import * as types from '../actions/actionTypes';
export function* fetchPost(action){
try{
yield put(actions.apiRequest());
const [post] = yield [call(service.getPostApi, action.postId)];
yield put(actions.apiRequestSucceeded(post));
} catch(e){
yield put(actions.apiRequestFailed());
}
}
export function* watchApiRequest() {
yield takeEvery(types.FETCH_POST, fetchPost);
}
actions
import * as types from './actionTypes';
export const fetchPost = (postId) => ({
type: types.FETCH_POST,
postId,
});
export const apiRequest = () => {
return {
type: types.API_REQUEST
}
}
export const apiRequestSucceeded = (post) => {
return {
type: types.API_REQUEST_SUCCEEDED,
post
}
}
export const apiRequestFailed = () => {
return {
type: types.API_REQUEST_FAILED
}
}
reducer
import * as types from '../actions/actionTypes';
const initialState = {
apiMsg: '',
postId: 1,
fetching: false,
post: null
};
export default function getPostData(state = initialState, action) {
switch (action.type) {
case types.API_REQUEST:
return {
...state,
apiMsg: 'API call request!',
fetching: true
}
case types.API_REQUEST_SUCCEEDED:
return {
...state,
apiMsg: 'API called succeeded!',
fetching: false,
postId: action.post.id,
post: action.title
};
case types.API_REQUEST_FAILED:
return {
...state,
apiMsg: 'API called failed!',
fetching: false,
};
default:
return state;
}
}
the component page
import React, { Component } from 'react';
import { View, Text} from 'react-native';
import { connect } from 'react-redux';
import {fetchPost} from './Actions/apiTesterActions';
class TestPage extends Component {
constructor() {
super();
}
componentDidMount() {
this.props.fetchPost(1)
}
render() {
const { postId, fetching, post } = this.props;
console.log('Test page props', postId, fetching, post);
return (
<View>
<Text>Test Page Works! </Text>
</View>
)
}
}
const mapStateToProps = (state) => {
return {
postId: state.getPostData.postId,
fetching: state.getPostData.fetching,
post: state.getPostData.post
}
};
export default connect(mapStateToProps, {fetchPost})(TestPage);
I am still learning Redux, and now redux-saga, so I don't fully understand the structure/hierarchy, but I am learning and any advice is helpful. Thank you
EDIT:
I am using this redux saga api call example as a guide.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { Provider } from 'react-redux';
import configureStore from './ReduxTest/Store/configureStore';
import rootSaga from './ReduxTest/sagas';
const store = configureStore();
store.runSaga(rootSaga)
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
registerServiceWorker();
saga/index.js
import {fork, all} from 'redux-saga/effects';
import {watchApiRequest} from './apiTester';
export default function* rootSaga() {
yield all [
fork(watchApiRequest)
]
}
After some time with a lot of debugging, I have figured the problem.
When I first started creating the application, I got the following error...
[...effects] has been deprecated in favor of all([...effects]), please update your code
As the yield all [...] was deprecated, I changed my code without taking it into consideration, I was happy the error went, but didn't realize how much of an impact it would have on my application.
(wrong) saga/index.js
import {fork, all} from 'redux-saga/effects';
import {watchApiRequest} from './apiTester';
export default function* rootSaga() {
yield all [
fork(watchApiRequest)
]
}
(right) saga/index.js
import {fork, all} from 'redux-saga/effects';
import {watchApiRequest} from './apiTester';
export default function* rootSaga() {
yield all ([
fork(watchApiRequest)
])
}
As You can see it needed to be wrapped in brackets yield all ([...])
You will get the deprecated error but your code will still work. I am unsure how to fix the deprecated error.
If someone knows how to get rid of the deprecated error than that would great.
I have a session reducer (using the redux-session library) which uses middleware to recover the state from the localstore. I can see from debugging tools that this is working as intended, however it is being replaced by my user reducer's initial state.
I feel I should be using preloadedState, but I cant get the result of a reducer into createStore?
storedState is being restored correctly (I can log it into console).
session: {user: {data: bhBSh}}, user: {data: null}
I cant see the best way to copy 'session' back to 'user' when the page is reloaded?
Session reducer:
function sessionReducer (state = {}, action) {
switch (action.type) {
case 'LOAD_STORED_STATE':
console.log(action.storedState); //Working!!!!!
return action.storedState;
default:
return state;
}
}
User reducer:
import { fromJS } from 'immutable';
import {
USER_LOGGING_IN,
USER_LOGGED_IN,
USER_LOGGED_OUT,
} from '../../constants';
const userInitialState = fromJS({
data: null,
isLoading: false,
});
function userReducer(state = userInitialState, action) {
switch (action.type) {
case USER_LOGGING_IN:
return state
.set('isLoading', true);
case USER_LOGGED_IN:
return state
.set('data', action.payload)
.set('isLoading', false);
case USER_LOGGED_OUT:
return userInitialState;
default:
return state;
}
}
export default userReducer;
export default function createReducer(injectedReducers) {
return combineReducers({
session: sessionReducer,
user: userReducer,
...injectedReducers,
});
}
configureStore:
export default function configureStore(history, session) {
session,
routerMiddleware(history),
thunkMiddleware
];
const enhancers = [
applyMiddleware(...middlewares),
];
//compose enhancers removed for readability
const store = createStore(
createReducer(),
//preloaded state??
composeEnhancers(...enhancers)
);
store.injectedReducers = {}; // Reducer registry
return store;
}
app.js
/**
* app.js
*
* This is the entry file for the application, only setup and boilerplate
* code.
*/
// Needed for redux-saga es6 generator support
import 'babel-polyfill';
// Import all the third party stuff
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import FontFaceObserver from 'fontfaceobserver';
import createHistory from 'history/createBrowserHistory';
import { createSession } from 'redux-session';
import 'sanitize.css/sanitize.css';
// Import root app
import App from 'containers/App';
// Import Language Provider
import LanguageProvider from 'containers/LanguageProvider';
// Load the favicon, the manifest.json file and the .htaccess file
/* eslint-disable import/no-webpack-loader-syntax */
import '!file-loader?name=[name].[ext]!./images/favicon.ico';
import '!file-loader?name=[name].[ext]!./images/icon-72x72.png';
import '!file-loader?name=[name].[ext]!./images/icon-96x96.png';
import '!file-loader?name=[name].[ext]!./images/icon-120x120.png';
import '!file-loader?name=[name].[ext]!./images/icon-128x128.png';
import '!file-loader?name=[name].[ext]!./images/icon-144x144.png';
import '!file-loader?name=[name].[ext]!./images/icon-152x152.png';
import '!file-loader?name=[name].[ext]!./images/icon-167x167.png';
import '!file-loader?name=[name].[ext]!./images/icon-180x180.png';
import '!file-loader?name=[name].[ext]!./images/icon-192x192.png';
import '!file-loader?name=[name].[ext]!./images/icon-384x384.png';
import '!file-loader?name=[name].[ext]!./images/icon-512x512.png';
import '!file-loader?name=[name].[ext]!./manifest.json';
import 'file-loader?name=[name].[ext]!./.htaccess'; // eslint-disable-line import/extensions
/* eslint-enable import/no-webpack-loader-syntax */
import configureStore from './configureStore';
// Import i18n messages
import { translationMessages } from './i18n';
// Import CSS reset and Global Styles
import './global-styles';
// Observe loading of Open Sans (to remove open sans, remove the <link> tag in
// the index.html file and this observer)
const openSansObserver = new FontFaceObserver('Open Sans', {});
// When Open Sans is loaded, add a font-family using Open Sans to the body
openSansObserver.load().then(() => {
document.body.classList.add('fontLoaded');
}, () => {
document.body.classList.remove('fontLoaded');
});
// Create redux store with history
const history = createHistory();
const session = createSession({
ns: 'test001',
selectState (state) {
return {
user: state.toJS().user
};
}
});
const store = configureStore(history, session);
const MOUNT_NODE = document.getElementById('app');
const render = (messages) => {
ReactDOM.render(
<Provider store={store}>
<LanguageProvider messages={messages}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</LanguageProvider>
</Provider>,
MOUNT_NODE
);
};
if (module.hot) {
// Hot reloadable React components and translation json files
// modules.hot.accept does not accept dynamic dependencies,
// have to be constants at compile-time
module.hot.accept(['./i18n', 'containers/App'], () => {
ReactDOM.unmountComponentAtNode(MOUNT_NODE);
render(translationMessages);
});
}
// Chunked polyfill for browsers without Intl support
if (!window.Intl) {
(new Promise((resolve) => {
resolve(import('intl'));
}))
.then(() => Promise.all([
import('intl/locale-data/jsonp/en.js'),
import('intl/locale-data/jsonp/de.js'),
]))
.then(() => render(translationMessages))
.catch((err) => {
throw err;
});
} else {
render(translationMessages);
}
// Install ServiceWorker and AppCache in the end since
// it's not most important operation and if main code fails,
// we do not want it installed
if (process.env.NODE_ENV === 'production') {
require('offline-plugin/runtime').install(); // eslint-disable-line global-require
}
As you can see from redux-session docs, the only thing this library tries to do to restore saved state is dispatching LOAD_STORED_STATE (which can be customized) action. Restoring your state when the action is dispatched is up to you. The simplest way to restore user state is to handle this action in your userReducer, so that it will look something like:
function userReducer(state = userInitialState, action) {
switch (action.type) {
case LOAD_STORED_STATE:
return fromJS(action.storedState);
case USER_LOGGING_IN:
return state
.set('isLoading', true);
case USER_LOGGED_IN:
return state
.set('data', action.payload)
.set('isLoading', false);
case USER_LOGGED_OUT:
return userInitialState;
default:
return state;
}
}
I'm trying setup a Redux + React Router app. I think the problem is with ImmutableJS, but I do not understand how to resolve it.
client.js
import { fromJS } from 'immutable'
import React from 'react'
import { render, unmountComponentAtNode } from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import { Provider } from 'react-redux'
import { match, Router, browserHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import { createStore, combineReducers, compose, applyMiddleware } from 'redux'
import { routerReducer, routerMiddleware } from 'react-router-redux'
function createSelectLocationState(reducerName) {
let prevRoutingState;
let prevRoutingStateJS;
return (state) => {
const routingState = state.get(reducerName); // or state.routing
if (!routingState.equals(prevRoutingState)) {
prevRoutingState = routingState;
prevRoutingStateJS = routingState.toJS();
}
return prevRoutingStateJS;
};
}
function configureStore(history, initialState) {
const reducer = combineReducers({
routing: routerReducer
});
return createStore(
reducer,
initialState,
compose(
applyMiddleware(
routerMiddleware(history)
)
)
);
}
const initialState = fromJS(window.__INITIAL_STATE__);
const store = configureStore(browserHistory, initialState);
const history = syncHistoryWithStore(browserHistory, store, {
selectLocationState: createSelectLocationState('routing')
});
const rootNode = document.getElementById('root');
const renderApp = () => {
const routes = require('./routes');
match({ history, routes }, (error, redirectLocation, renderProps) => {
render(
<AppContainer>
<Provider store={store}>
<Router {...renderProps} />
</Provider>
</AppContainer>,
rootNode
);
});
};
// Enable hot reload by react-hot-loader
if (module.hot) {
const reRenderApp = () => {
try {
renderApp();
} catch (error) {
const RedBox = require('redbox-react').default;
render(<RedBox error={error} />, rootNode);
}
};
module.hot.accept('./routes', () => {
setImmediate(() => {
// Preventing the hot reloading error from react-router
unmountComponentAtNode(rootNode);
reRenderApp();
});
});
}
renderApp();
I get this error:
Uncaught TypeError: state.get is not a function
In state this object
I use "react": "^15.3.2", "redux": "^3.6.0", "react-router": "^3.0.0"
UPDATE 1
I now use combineReducers from redux-immutable:
import {combineReducers} from 'redux-immutable'
But get an error:
Uncaught TypeError: routingState.equals is not a function
Here:
UPDATE 2
I fixed hereinabove issue, but there one more error
All code i posted in this repository
The problem stays at src/index.js file with the require statement of route.js.
When you require es6 module which has default, you have to use the default from required module. Something like,
const routes = require('./routes').default;
This fixed your issues without any other change on your git repo.
The combineReducers you are using is not using immutable. Each branch is immutable by setting fromJS(blah) but not on the highest level of your state. Use redux-immutable instead:
import {combineReducers} from 'redux-immutable';