window is not defined - Next.js 13 - Client Component in Server Component - - next.js

Leaflet is imported in a file that's imported into a client component, so why is the server running it and throwing this error?
It actually does work after a retry and eventually renders site fine.
I tried using a dynamic import inside useEffect... no dice.
ReferenceError: window is not defined
at eval (webpack-internal:///(sc_client)/./node_modules/leaflet/dist/leaflet-src.esm.js:305:17)
at Object.(sc_client)/./node_modules/leaflet/dist/leaflet-src.esm.js (path/to/app.next/server/app/page.js:473:1)
at __webpack_require__ (path/to/app.next/server/webpack-runtime.js:33:42)
at eval (webpack-internal:///(sc_client)/./src/js/index.js:5:89)
at Object.(sc_client)/./src/js/index.js (path/to/app.next/server/app/page.js:1845:1)
at __webpack_require__ (path/to/app.next/server/webpack-runtime.js:33:42)
at eval (webpack-internal:///(sc_client)/./src/components/Foo.jsx:9:70)
at Object.(sc_client)/./src/components/Foo.jsx (path/to/app.next/server/app/page.js:1834:1)
# more logs ...
// app/page.js
import Foo from '#components/Foo';
export default function Base() {
return (
<main>
<Foo />
</main>
);
}
// components/Foo.jsx
'use client';
import { useEffect } from 'react';
import { test } from '../js/index.js';
export default function Foo() {
useEffect(() => {
test();
}, []);
return <div>foo</div>;
}
// js/index.js
// Error thrown here cause calling window
import * as L from 'leaflet/dist/leaflet-src.esm.js';
const test = () => {
console.log(L);
};
export { test };

Related

Vue3 Composition API - Pinia store returns "Uncaught (in promise) TypeError: ____ is not a function"

Searched all over SO, very little information.
The store:
import { defineStore } from 'pinia'
import axios from 'axios'
export const useScanStore = defineStore({
id: 'scan',
state: () => ({
scans: [],
scan : null,
loading: false,
error: null,
messages : []
}),
getters: {
getScans : state => state.scans,
},
subscriptions: {
},
actions: {
async updateScan(id,data) {
// code here that works
}
// trimmed for shortness
}
THE COMPONENT
<template>
<div>
<q-btn color="orange" text-color="white" size="sm" #click="stopScan" class="q-mr-sm">
STOP
</q-btn>
</div>
</template>
<script setup>
import {useScanStore} from "#/stores/scan";
const scanStore = useScanStore();
// trimmed
async function stopScan(id){
const rerunResponse = await scanStore.updateScan(id, {status: 'failed'}) //<<< ERROR HERE
}
</script>
The frustrating part is that THIS EXACT code works in other component. So that function DOES exist.
It's imported IDENTICALLY in component where it works.
Error points at that line in function.
Why am I getting this error? I reduced component to just a single function, button and call.
There are NO OTHER ERRORS in console. Just this (when button is pressed):
I ended up destroying and rebuilding my docker compose (Docker image) and it started working.

Vue3 Cannot read globalProperties in component

I am converting an existing app from vue 2 to 3.
I am having troubles with accessing globalProperties in components. In some instances using this.$propertyname returns undefined
In my main.js file:
import { createApp } from 'vue'
import App from './App.vue'
import {
appPageLoader
} from '#/store/reactives'
function mount(el){
let app = createApp(App)
app.config.globalProperties.$pgLoader = appPageLoader
// This console log returns proper value
console.log('^^^', appAnnouncer, app.config.globalProperties.$pgLoader)
app.mount(el)
}
mount('#app')
appPageLoader.js
This file contains a reactive object which we can import and assign to globalProperties $pgLoader
import { reactive } from "vue";
let pgLoader = {
pageLoadAnchor: null,
setFocusToTop () {
if (this.pageLoadAnchor instanceof HTMLElement) {
this.pageLoadAnchor.focus()
} else {
console.log('Cannot setFocusToTop() - pageLoadAnchor not found!')
}
}
}
let ReactivePageLoader = reactive(pgLoader)
export default ReactivePageLoader;
app.vue
When trying to access globalProperties using this.$property, I get undefined in component:
import { getCurrentInstance } from "vue";
mounted() {
this.$pgLoader.pageLoadAnchor = this.$refs.pageLoadAnchor; <- this.$pgLoader returns undefined
getCurrentInstance().appContext.config.globalProperties.$pgLoader = this.$refs.pageLoadAnchor; <- works but cumbersome
},

CodeMirror on Vue3 has a problem when setValue is kicked

I'm trying to use CodeMirror on Vue3 and the problem occurs when I call doc.setValue().
The Problem is following:
Cursor position is broken when doc.setValue() is called
CodeMirror throws an exception when continuing editing
The exception is here.
Uncaught TypeError: Cannot read property 'height' of undefined
at lineLength (codemirror.js:1653)
at codemirror.js:5459
at LeafChunk.iterN (codemirror.js:5623)
at Doc.iterN (codemirror.js:5725)
at Doc.iter (codemirror.js:6111)
at makeChangeSingleDocInEditor (codemirror.js:5458)
at makeChangeSingleDoc (codemirror.js:5428)
at makeChangeInner (codemirror.js:5297)
at makeChange (codemirror.js:5288)
at replaceRange (codemirror.js:5502)
How should I solve this?
~~~
Versions are CodeMirror: 5.61.1, Vue.js: 3.0.11
My code is following:
index.html
<div id="app"></div>
<script src="./index.js"></script>
index.js
import { createApp } from 'vue';
import App from './App';
const app = createApp(App);
app.mount('#app');
App.vue
<template>
<div>
<button #click="click">Push Me</button>
<textarea id="codemirror"></textarea>
</div>
</template>
<script>
import CodeMirror from 'codemirror/lib/codemirror.js';
import 'codemirror/lib/codemirror.css';
// import codemirror resources
import 'codemirror/addon/mode/overlay.js';
import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/mode/gfm/gfm.js';
export default {
data () {
return {
cm: null
}
},
mounted () {
this.cm = CodeMirror.fromTextArea(document.getElementById('codemirror'), {
mode: 'gfm',
lineNumbers: true,
});
},
methods: {
click (event) {
this.cm.getDoc().setValue('foo\nbar');
}
}
}
</script>
Thanks.
UPDATES
First, this problem also occurs when I used replaceRange() with multiline.
Unfortunately, I couldn't find any solution. So I tried to find another way.
My solution is recreating Codemirror instance with a textarea that has new content.
It works well.
// Remove old editor
this.cm.toTextArea();
// Get textarea
const textarea = document.getElementById('codemirror');
// Set new content
textarea.value = 'foo\nbar';
// Create new editor
this.cm = CodeMirror.fromTextArea(textarea, { /** options */ });
I found a method, you can use toRaw to get the original Object from Proxy,and this method can be also used in monaco-editor
import { toRaw } from 'vue'
import CodeMirror from 'codemirror/lib/codemirror.js';
import 'codemirror/lib/codemirror.css';
// import codemirror resources
import 'codemirror/addon/mode/overlay.js';
import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/mode/gfm/gfm.js';
export default {
data () {
return {
cm: null
}
},
mounted () {
this.cm = CodeMirror.fromTextArea(document.getElementById('codemirror'), {
mode: 'gfm',
lineNumbers: true,
});
},
methods: {
click (event) {
toRaw(this.cm).setValue('foo\nbar');
}
}
}
Another way,you don't have to define cm in data, just use this.cm
data () {
return {
//cm: null
}
},

jest for testing describe is not a function

I have made an app using react and redux, I have some components plus their containers and also an action and a reducer.
I am writing a test for one of my containers using enzyme, chai and jest,
when I try to run my test it gives the following error:
Test suite failed to run
TypeError: jest_1.describe is not a function
here is my test file:
import * as React from "react";
import { shallow, mount, render } from 'enzyme';
import * as Sinon from "sinon";
import MinPriceContainer from "../../src/containers/SearchForm/containers/MinPriceContainer";
import MaxPriceContainer from "../../src/containers/SearchForm/containers/MaxPriceContainer";
import { expect } from "chai";
import { it, before, describe } from 'jest';
describe('<MinValueInput />', () => {
let minValueInput;
beforeEach(() => {
minValueInput = shallow(<MinPriceContainer />);
})
// it('renders component correctly', () => {
// expect(tabs.find('.MinPriceComponent').exists()).toBe(true);
// });
it('cannot have a non numeric value', () => {
minValueInput = shallow(<MinPriceContainer minimumPriceSelected="i am a string not a number" />);
expect(minValueInput.find('.error').text()).equal("You cannot use a non numeric value");
});
it('cannot have a value less thn zero', () => {
minValueInput = shallow(<MinPriceContainer minimumPriceSelected={-20} />);
expect(minValueInput.find('.error').text()).equal("value cannot be less than zero");
});
it('it can not have a value greater than maxValue', () => {
minValueInput = shallow(<MinPriceContainer minimumPriceSelected={99} maximumPriceSelected={80}/>);
expect(minValueInput.find('.error').text()).equal("value cannot be greater than price");
});
});
how can I fix this, is this related to my importS?
is the test written correctly?
the component that I am testing has a number value called minPrice and it can not be negative and also it should not be more than another component that is called maxPrice, also it should only accepts numbers!
I take it you're using ts-jest?
replace
import { it, before, describe } from 'jest';
with
import 'jest';

Redux action is not being fired

Redux action changePictogramsKeyword is not being fired.
This is the file where I define my action and reducer (redux/module/keyword.js):
export const CHANGE_PICTOGRAMS_KEYWORD = 'CHANGE_PICTOGRAMS_KEYWORD'
export function changePictogramsKeyword (keyword) {
return {
type: CHANGE_PICTOGRAMS_KEYWORD,
keyword
}
}
// Updates error message to notify about the failed fetches.
export default function pictogramsKeyword (state = '', action) {
switch (action.type) {
case CHANGE_PICTOGRAMS_KEYWORD:
return action.keyword
default:
return state
}
}
My root reducer:
import { combineReducers } from 'redux'
import { routerReducer as router } from 'react-router-redux'
import locale from './modules/locale'
import errorMessage from './modules/error'
import pictogramsKeyword from './modules/keyword'
export default combineReducers({
locale,
router,
pictogramsKeyword,
errorMessage
})
So with the devTools I can check that my initialState is as I expected from the rootReducer:
locale:"en"
router:{} 1 key
pictogramsKeyword:""
errorMessage:null
This is the code of the view where I connect to Redux Store. Component SearchBox is in charge of firing the action changePictogramsKeyword:
import React, {Component, PropTypes} from 'react'
import SearchBox from 'components/SearchBox.js'
import { connect } from 'react-redux'
import { changePictogramsKeyword } from 'redux/modules/keyword'
class SearchPictogramsView extends Component {
handleDismissClick (e) {
this.props.resetErrorMessage()
e.preventDefault()
}
render () {
const { children, inputValue } = this.props
return (
<div>
<SearchBox value={inputValue} onChange={changePictogramsKeyword} />
{children}
</div>
)
}
}
SearchPictogramsView.propTypes = {
inputValue: PropTypes.string.isRequired,
children: PropTypes.node
}
function mapStateToProps (state, ownProps) {
return {
errorMessage: state.errorMessage,
inputValue: state.pictogramsKeyword
}
}
export default connect(mapStateToProps, {
resetErrorMessage, changePictogramsKeyword
})(SearchPictogramsView)
This is the code of the SearchBox component. AutoComplete is a material-ui component. onUpdateInput method gets fired everytime I press a key, however changePictogramsKeyword is not being fired (i see nothing through the dev tools)
import React, {Component, PropTypes} from 'react'
import AutoComplete from 'material-ui/lib/auto-complete'
import RaisedButton from 'material-ui/lib/raised-button'
class SearchBox extends Component {
constructor (props) {
super(props)
this.handleUpdateInput = this.handleUpdateInput.bind(this)
}
handleUpdateInput = (t) => {
console.log(t)
this.props.onChange(t)
}
render () {
return (
<div>
<AutoComplete onUpdateInput={this.handleUpdateInput} searchText={this.props.value} />
</div>
)
}
}
SearchBox.propTypes = {
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
}
export default SearchBox
Right now, your action only gets called, but not dispatched because you're not mapping the actions correctly in the connect() call. (see the official documentation for more information)
In your SearchPictogramsView, change the mapDispatchToProps function of the connect() call to return an object with the wrapped functions:
export default connect(mapStateToProps, (dispatch) => {
return {
resetErrorMessage: () => dispatch(resetErrorMessage()),
changePictogramsKeyword: () => dispatch(changePictogramsKeyword())
};
})(SearchPictogramsView)
You can clean it up by making mapDispatchToProps its own function too:
function mapDispatchToProps(dispatch) {
return {
resetErrorMessage: () => dispatch(resetErrorMessage()),
changePictogramsKeyword: () => dispatch(changePictogramsKeyword())
};
}
export default connect(mapStateToProps, mapDispatchToProps)(SearchPictogramsView)
Let me know if that works!
It was really in the docs:
If an object is passed, each function inside it will be assumed to be
a Redux action creator. An object with the same function names, but
with every action creator wrapped into a dispatch call so they may be
invoked directly, will be merged into the component’s props
When I wrote:
<SearchBox value={inputValue} onChange={changePictogramsKeyword} />
Now is:
<SearchBox value={inputValue} onChange={this.props.changePictogramsKeyword} />
So I really call the dispatch of the action and not just the action!

Resources