Importing CSS helper function that uses 'document' in NextJS - next.js

I am using styled-components. I'd like to import a function that helps create fluid styles. My function uses the following:
const root = document.querySelector('html');
const pixelsPerRem = Number(getComputedStyle(root).fontSize.slice(0, -2));
When I import my function using
`const clampBuilder = dynamic(() => import('utils/clampBuilder'), {
ssr: false,
});`
I see clampBuilder is not a function. I understand that since NextJS is SSR, there is no document. I am wondering how I could import my helper function or somehow use it to calculate what I need.
Function gist: https://gist.github.com/RockinRonE/b163549f684c1b4841941a6054888602

Above error says that your clampBuilder is not a function and it doesnt seems to be any issue with SSR or with document.
can you try updating dynamic import as following:
const clampBuilder = dynamic(import('utils/clampBuilder'), { ssr: false })

I ended up removing the two lines shown above from the function and set pixelsPerRem to 16 since that's the default for most browsers. It may not be perfect, but it is good enough!

Related

Vue - using props on custom elements fails using createApp and mount?

We would like to pass props to custom elements that uses createApp
// index.html
<div id="my-root">
<my-element prop1="abc"></my-element>
</div>
// my-element.vue
<script lang="ts" setup>
const props = defineProps<{ prop1: number }>();
</script>
<template>
{{props.prop1}}
</template>
This works fine, but as our custome element get bigger we would like to register components and use e.g pinia and other tools. Do use those we need to add createApp and mount it. But then prop1 is always undefined
// main.ts
import ...<lots of imports>
import AppCe from "./AppWebComponent.ce.vue";
import { createPinia } from "pinia";
// Adding code below is causing prop1 to be undefined - if we skip this part, prop1 works fine
const pinia = createPinia();
const app = createApp(App);
app.use(pinia).use(ConfirmDialog);
app.component(...<lots of components>);
app.mount("#my-root");
const ceApp = defineCustomElement(AppCe);
customElements.define("my-element", ceApp);
update:
Here's a sample without: https://stackblitz.com/edit/vue3-script-setup-with-vite-56rizn?file=src/my-element/my-element-main.js
And here's a sample with the createApp: https://stackblitz.com/edit/vue3-script-setup-with-vite-gtkbaq?file=index.html
Any idea on how we could solve this?
We have a fallback, that is to do a getElementById and read the attribute value in the mounted callback - but that is not an optimal solution.
Thanks for any ideas!
update2:
Here's an attempt using #duannex suggestion. We're getting closer, the app is availible, components registered, but still no sigar. : https://stackblitz.com/edit/vue3-script-setup-with-vite-ofwcjt?file=src/my-element/defineCustomElementWrapped.js
Based on update2 with the wrapped defineCustomElement; Just pass the props to the render function:
render() {
return h(component, this.$props)
},
https://stackblitz.com/edit/vue3-script-setup-with-vite-vfdnvg?file=src/my-element/defineCustomElementWrapped.js

Emotion's CSS props not working with Create-React-App

I wanted to use Emotion with CRA so I installed it following the documentation and tried to use the css prop as shown in the example below :
import { FC } from "react";
import { TypographyProps } from "./Typography.propTypes";
import * as styles from "./Typography.styles";
export const Typography: FC<TypographyProps> = ({
children,
}) => {
return <h1 css={styles.typography}>{children}</h1>;
};
but it didn't work.
By inspecting the code, I found this :
<h1 css="You have tried to stringify object returned from `css` function.
It isn't supposed to be used directly (e.g. as value of the `className` prop),
but rather handed to emotion so it can handle it (e.g. as value of `css` prop).">
Header</h1>
I tried following the solution from this blog article, but still didn't work :
https://harryhedger.medium.com/quick-how-to-use-the-emotion-css-prop-with-create-react-app-5f6aa0f0c5c5
Any thing I can do to fix it?
Thanks!
The easiest way to fix this is to add the following line at the beginning of your file.
/** #jsxImportSource #emotion/react */

How to test React dynamic style prop?

Am teaching myself React and am starting on testing. Using the recommended stuff from the docs... create-react-app, jest, testing-library/react. I have a component that renders a dynamic style, something like this
const ScalingDiv = (props) => (
<StyledDiv size={props.size || 42}>
<OtherEl>
{props.text}
</OtherEl>
</StyledDiv>
);
I would like to verify that my logic in there is working correctly (that 42 is used as a fallback size). I cannot find any examples or docs of this. I had hoped that something like this would work-
test('check fallback size', async () => {
const {container} = render(<ScalingDiv/>);
expect(container.firstChild).toHaveAttribute('size', 42);
});
But I haven't found any combination of matchers and queries that returns ANY attributes. Then I tried to just check the style directly using jest-dom, but toHaveStyle('this_isnt_valid_css: 199') passes- I couldn't stick anything in there to get it to fail. So... what is the right way to do this?
It's not attribute but prop. So we can refer to prop() and props() methods like
expect(container.firstChild.prop('size')).toEqual(42);
or
expect(container.firstChild.props()).toEqual({
size: 42
});

How to use react-jss within react class Components?

In react-jss documentation, the authors have written:
'HOC based API is deprecated as of v10 and will be removed in v11.'
This means, as far as I understand, that such HOC functionality as injectSheet and withStyles will no longer be available in V11.
The new react-based stylesheet generating functions seem to be all based on react hooks. The function createUseStyles seemed very promising to myself and my team, until upon looking further into the source code we realised that it was only available within functional components, as it makes use of hooks.
The Problem
As a team we still make heavy use of React Class components and have no plans to move completely to hooks, not because hooks aren't useful, but because sometimes functional components aren't the best or most organised solution to writing a component.
Perhaps I'm missing something-- but it seems like there is now no solution left for React Class based components, other than writing our own manual implementation from core jss.
What solutions are there for a developer to make use of react-jss in a way similar to that achieved by createUseStyles, keeping up with the latest version of react-jss, being able to pass dynamic props, and etc. without writing a manual implementation?
While not specific to JSS, keep in mind that you can always use a tiny wrapper to convert any Hook to render prop or a HOC.
Converting Hook to a render prop is described here: https://reacttraining.com/blog/using-hooks-in-classes/
You can use a similar approach to convert any Hook to a HOC.
import { Classes } from 'jss';
import { createUseStyles } from 'react-jss';
First, lets create a more type safe function for creating styles.
export function createStyles(classes: { [name: string]: Partial<CSSStyleDeclaration> }) {
return createUseStyles(classes as any);
}
Secondly, we'll create a simple wrapper to allow hooks for our components.
function Styles<T extends string | number | symbol>(props: { styles: () => Classes<T>, children: (classes: Classes<T>) => ReactElement }) {
const classes = props.styles();
return props.children(classes);
}
Example
const styles = createStyles({
title: {
fontSize: '25px',
textTransform: 'uppercase'
},
message: {
color: 'red'
}
});
export const App = () => (
<Styles styles={styles}>
{classes => (
<Fragment>
<h1 className={classes.title}>Title</h1>
<p className={classes.message}>message</p>
</Fragment>
)}
</Styles>
);
Output

useSelector with React.memo vs connect

referring from the link.
https://react-redux.js.org/next/api/hooks#performance
what i understand the benefit of useSelector hook, is to avoid wrapper hell. Wrapper hell is happening due to the usage of connect HOC. If we have to use React.memo HOC with useSelector due to perfomance reason, would it be better approach to simply use connect HOC instead? Because in any case we would have to be in hell of wrappers. If the hell is not by connect then would be by React.memo.
Any one please explain the benefit of React.memo over connect.
Well, first, interesting enough although React.memo is a HOC it does not create the same nesting as connect does. I have created a test code:
import React from "react";
import ReactDOM from "react-dom";
import {connect, Provider} from 'react-redux'
import { createStore } from 'redux'
import "./styles.css";
const MemoComponent = React.memo(function MyMemo() {
return <div>Memo</div>;
});
const ConnectedComponent = connect(null,null)(function MyConnected() {
return <div>ReduxConnectComponent</div>;
})
const store = createStore(()=>{},{})
function App() {
return (
<Provider store={store}>
<MemoComponent />
<ConnectedComponent/>
</Provider>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And here is the structure rendered:
We can see that a content for connect is rendered deeper.
Second, the docs say:
by default useSelector() will do a reference equality comparison of the selected value when running the selector function after an action is dispatched, and will only cause the component to re-render if the selected value changed. However, unlike connect(), useSelector() does not prevent the component from re-rendering due to its parent re-rendering, even if the component's props did not change.
that means the component which useSelector will not be re-rendered when unrelated parts of the store change. And this is the most important part of the optimization. Whether optimizing with React.memo or not is now completely depends on your decision and in most cases, it simply is not needed. We use React.memo only in cases when the component is very expensive to render.
To summarize, connect wrapper was required to connect to the store. With useSelector we do not have to wrap anymore. We still need to wrap with React.memo in rare cases when we need to optimize some heavy components. The work of React.memo was also done by connect but in most cases, it was premature optimization.
I have been trying to get an answer for quite some time but the answers I got weren't clear. Although the theory in the Redux documentation isn't complicated: useSelector uses strict equality === and connect uses shallow equality to determine. So in both cases, if you are "pulling" a primitive value from your Redux state (number, string, boolean) you will be having the same outcome. If values haven't changed none of the components will rerender. If you are "pulling" non-primitives (arrays or objects) and the values haven't changed for both cases (useSelector, connect), then the component that uses useSelector will still rerender as of course [] === [] will always be false, as they are referencing different arrays, where as the connected component will NOT rerender. Now in order to make useSelector behave similarly and not rerender, you can do this:
const object = useSelector(state => state.object, shallowEqual) You can import shallowEqual from react-redux. Or alternatively use a memoized version of that piece of state by using the reselect library:
const makeGetObject = () => createSelector(state => state.object, object => object)
and add it to your selector such as: const object = useSelector(state => state.object, makeGetObject); I have created this codesandbox when I was trying to get at the bottom of it (check the comments at the WithUseSelector component): useSelector vs connect()
I just customized useSelector hook to avoid that and it works nice
import { useSelector, useDispatch } from 'react-redux'
import { _lodash } from '../../../lodash'
export const useCloneSelector = (selector = (obj) => obj) => {
const selectWithClonedState = (state = {}, ...others) => selector(_lodash.cloneDeep(state), ...others)
return useSelector(selectWithClonedState, _lodash.isEqual)
}
export { useDispatch, useSelector }

Resources