How to prevent re-render caused because of calling hook useSelector()? - javascript

EDIT It caused by <React.StrictMode></React.StrictMode> in index.js. I am not sure why but it is odd.
I noticed hook useSelector() caused the app re-render needlessly. Is this expected? If yes, should I drop using redux-toolkit-js?
I haven't tested this behavior on React Native but I think re-rendering in React Native will become an issue.
Hook useSelector caused the app to re-render 2 times more and it compounds, meaning If the app without Redux will re-render only 2 times, caused by a state update, simply calling useSelector() will cause the app to re-render 4 times.
This is the steps I took to reproduce the problem:
npx create-react-app my-app --template redux
cd my-app
npm start
add console.log in App.js and features/counter/Counter.js
let i = 0;
function App() {
i++
console.log("App()", i)
...
}
Check your browser DevTools's console.

React does an extra render in development environments in strict mode to help you find bugs and do some checks for you. It doesn't do this in a production build.
From the docs for strict mode:
Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer

Related

React Component - Cannot read properties of null (reading 'useState')

I am building a little local dev/testing/documentation environment for some components which are used across different projects and so want to create them as individual npm packages.
Everything was working perfectly until I tried to use useState() in one of the components. Add this created the following errors:
Invalid hook call. Hooks can only be called inside of the body of a function component.
TypeError: Cannot read properties of null (reading 'useState')
I feel this is strange and I can't figure out what is causing it. I also tested with other hooks to see if it was just useState that was the problem but others such as useEffect and useRef also have the same problem.
Project structure is:
/components (the components to develop/test/document
/component-group
/Component
index.js
Component.js
component.scss
package.json
/library (where all the components are developed/tested/documented)
/component1
/component2
/etc (all the components that make up the library)
webpack.config.js
package.json
etc...
Components are imported into the library using a relative path because I don't won't to have to publish them to npm and update the version locally every time a change is made and needs to be tested.
As for the code for the component where useState is causing problems, this is a basic version which still causes problems:
import React, { useState } from 'react';
const TestComponent = () => {
const [testState, setTestState] = useState("testing");
return (
<p>Hello World</p>
)
}
export default TestComponent
If I comment out the useState line then Hello World is displayed, if I uncomment the line then the errors appear.
Any ideas as to what might be wrong would be really appreciated.
Thank you in advance!

Using Vuex 4 modules in Vue 3 with TypeScript, and how to fix cyclical dependency linting error?

As of this writing, Vue 3.0 has reached it's first stable v3.0.0 'One Piece' release, with Vuex 4 being in v4.0.0-beta.4.
Unfortunately there is no official examples yet on how to use Vuex 4 modules in TypeScript...
As a further requirement, I want to have store modules state, mutations, getters, and actions in their own files. This makes it easier to manage the code when these modules grow.
I managed to piece together a working example repository in Github and Codesandbox.
By using the examples provided in these resources:
Vuex + TypeScript by Andrew in Dev.to
Gist javisperez/index.ts
Repo andrewvasilchuk/vuex-typescript
Vue 3 & Vuex 4: useStoreModule composable by Barylski in Dev.to
A complete guide to mapping in Vuex by LogRocket
However, a few quirks remains to be solved:
1. Resolving dependency cycle linting errors
Currently the typings in a module's index.ts, actions.ts, and getters.ts are dependent on importing RootState from the main store.
When using ESLint Airbnb linting config, I'm barraged with linting errors like (currently disabled by // eslint-disable-next-line rules in the repo and example):
Dependency cycle via #/store/modules/profile > eslint(import/no-cycle)
While this doesn't seem to affect the actual functioning of the store (or does it?), I'd like to know how to overcome this without needing to turn the rule off, or needing to use // eslint-disable-next-line import/no-cycle on those lines?
I haven't tried if this happens with Standard and Prettier linter configs, or is it related to Airbnb rules?
2. How to have a module without any actions?
I tried to have profile module configured without using any actions, however I was unable to get the types rights.
Currently the example code includes one NON_ACTION action type...
3. How to correctly use namespaced: true module option, and how it affects the usage syntax in components?
Currently profile store is configured with namespaced: true. In the App.vue I'm demonstrating it by using mapGetters, which takes a module name as the first parameter. This works.
However, documents module is without this option, because dispatch with the action type doesn't work anymore. It seems to be needing to be used with some other syntax variant which I was unable to find.
PS. Any further code polishing suggestion are much welcome as comments, answers, and pull requests!
Update 27/09/20: I just realized VS Code intellisense is not showing type information for the store instance after passing it from useStore function, when used inside component. Works if imported in .ts file.
I have published a package to help with using Vuex 4 with Typescript. It's not perfect, but it covers 95% of the issues we had. Any feedback would be appreciated.
It requires TS 4.1+ for the template literal support.
https://www.npmjs.com/package/typed-vuex-wrapper
FWIW the initial implementation was highly inspired by your start on modules, but expands that, and supports mapState/mapActions, etc with fully typed access. Requires TS 4.1 for the template literal support to allow fully safe namespaced access without magic strings.

Importing external React components to nextJS project

I have a functional component in my own library that I'm importing into a nextJS project, and for some reason it's not recognized as a react functional component.
Example of my library code:
import React, { useState } from 'react';
export function Dialog(){
const [open, setOpen] = useState(false);
return (<>
// some jsx logic
</>)
}
importing it in my nextJS component:
import { Dialog } from '#myNamespace/library';
When I try to use
<Dialog />
I get this error:
Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/warnings/invalid-hook-call-warning.html for tips about how to debug and fix this problem.
So I logged out a local react component with the Dialog and found that while the local react component seems to be on the namespace react__WEBPACK_IMPORTED_MODULE_1___default, my imported component just remains a plain function instead of a react component.
Any ideas as to why NextJS isn't importing my function as a react component?
EDIT:
Here's something really interesting: When I remove the hook, nextJS seems to think it is a react component. But when I put the hook in, it doesn't - and throws that error.
SOLUTION
For anyone who's interested - the issue was that my package was npm link into my project. So in that case there's issues with it not packaging up the components correctly.
It is possible that your react and react-dom isn't updated to the standard for hooks try yarn add react#18.6 react-dom#18.6

ESLint, Create React App and Unused Vars error

I have an application that is using CRA and having added redux into the mix I am now suddenly getting un-used vars linting errors when importing things like dispatch from redux.
Any help on why these might be coming back as unused would be really appreciated!
You don't need the second line:
import { dispatch } from 'redux'
dispatch is added when you connect a component with redux automatically.
The second import seems unneeded as well. The function that is making use of it is receiving it as part of its parameters already. The default state should be used to initialize the reducer instead.

ReferenceError: process is not defined when requiring Shelljs in ReactJS

I am trying to require shelljs in my core React component.
import React, { Component } from 'react';
import {render} from 'react-dom';
import Header from './components/Header';
const shell = require('shelljs');
class App extends Component {
render() {
console.log("First component mounting");
console.log("First component mounting");
return (
<Header />
)
}
}
render(<App />, document.getElementById('root'));
When I run
webpack build
I get no errors, then I run my server and I get the following console error.
I'm using jekyll as my server side. Currently transitioning from the normal jekyll implementation to React only.
React is well implemented cause i tested the Header component before importing the shelljs module
ReferenceError: process is not defined
I'm new to using modules in javascript, thanks in advance.
I'm going to guess you don't really mean to use your shell constant since you haven't referenced it anywhere within your React component. Shelljs looks like it's a tool specifically for the command line.
As for your error:
process is a global variable in the Node environment. Since React runs in the browser, and your component is going to render in the browser, process will not exist in the context of your component.
Try opening the Chrome DevTools (or the developer tools for whatever browser you use) and type in process. You'll get a TypeError because it doesn't exist. What does exist, however, is the global window variable.
Now, open the command line and type node to open the Node.js REPL.
Type process here, and you'll see that it's an object holding a lot of properties and values. Next, type window and press enter. window does not exist here because it only exists in the browser.
(Type Ctrl+C twice to exit Node btw. :])

Categories