I've seen somewhere in github people import *, I have no clue why he did so, for instance:
import * as React from 'react';
export const doSomething = () => {
return React.useMemo(() => {
return {
something: window.location.href
};
}, []);
};
He did the same for other packages. Why don't we do
import { useMemo } from 'react' ?
Both of the suggestions for using * or explicit imports are possible and will work as expected.
The asterix will import all components, hooks, and more artifacts that are located under the "react" library, so when using
import * from "react";
you'll have the freedom to use any type of hook or Component without an explicit import.
The best practice though is to import only modules that are relevant to your application or components
import React, { useMemo } from "react";
This approach will make sure you don't import unused components that will be heavy on your bundle size for production and will be flagged as dead code.
Ok, to expand my answer I will say: You have two options
import React, { useMemo } from 'react';
Benefits? You are just importing the things you need, also, your code will be a little bit shorter compared to the second option since you can use useMemo(); directly
Also this is the way reactjs.org presents their examples https://reactjs.org/docs/hooks-intro.html which is a big -GOOD PRACTICE- signal
import React from 'react';
it's seem similar to the first option but you are using React directly.
how to access useMemo()? React.useMemo(). So yes, you guessed, it's a little bit longer sintax that the first option, but i do not think this is a problem.
Also this is the way https://material-ui.com/components/text-fields/ material ui presents their examples. It's also a nice way to do it (and the one I use)
Related
I am fairly new to React and still wrapping my head around custom-hooks. I cam across a code where a custom hook was created to handle the component imports.
useComponentPalette.js
import {TodoEditor} from './components/TodoEditor'
import {TodoItem} from './components/TodoItem'
import {TodoList} from './components/TodoList'
import {CheckBox} from './components/CheckBox'
const defaultComponents = {
TodoEditor,
TodoItem,
TodoList,
CheckBox
}
export function useComponentPalette(){
return defaultComponents
}
And then in order to use the hook,
const {TodoItem, TodoList, Checkbox } = useComponentPalette()
My Question :- Does this approach provides any advantage over the regular imports in the component ? or this is an anti-pattern ?
How I usually import the components is as follows
import {TodoEditor} from './components/TodoEditor'
import {TodoItem} from './components/TodoItem'
import {TodoList} from './components/TodoList'
import {CheckBox} from './components/CheckBox'
function App(){
return(
<>
<TodoList/>
</>
)
}
It's not a good idea to use react hooks like this you can get the same result without react hook
// first file name.js
import {TodoEditor} from './components/TodoEditor'
import {TodoItem} from './components/TodoItem'
import {TodoList} from './components/TodoList'
import {CheckBox} from './components/CheckBox'
export default {
TodoEditor,
TodoItem,
TodoList,
CheckBox
}
//component file
import * as Component form 'first file name';
//<Component.TodoEditor/>
//or
import {TodoEditor} form 'first file name';
The way that I use react-hooks is for making my code more dry and increase it's readability, so react-hooks is not good fit for this kind of usage.
Hi #Sachin,
In my option, React JS use hook to manage reuse stateful logic between components. In other word, Hooks do well to encapsulating state and share logic. If you want to do some stateful logic or condition base logic with these components, then it's fine with that. But if you are using just without condition in the given components. Then, This Is useless for making the custom hook. You can do that without a custom hook in a simpler way.
Here is a simple way to do that:-
In components folder. I create index file, this is the entry point of all my exporting components
In that file. I export all my components, as you can see.
I use that components like this. It much better way. In my option.
import { Header, Footer, Sider } from "./components"
before using react custom hooks, we should be aware of the rationale behind it.
Customs hooks functionality was provided to reuse stateful logic. If logic doesn't require any state, we will use simple functions and if it is about components only there there are different patterns for making code general and scaleable.
So, there is no usage of custom hook in above case at all. For me, I would go with the following code for above scenario:
// components/index.tsx
import {Todo} from './todo'
import {CheckBox} from './components/CheckBox'
export {
Todo,
CheckBox
}
// componentns/todo/index.tsx
import {Editor} from './Editor'
import {Item} from './Item'
import {List} from './List'
const Todo = {
Editor,
Item,
List
}
export default Todo;
and usage will be like
import { Checkbox, Todo } from "components"
...
<Checkbox ... />
<Todo.List ...>
<Todo.Item ... >
</Todo.Editor ... />
</Todo.Item ... >
</Todo.List>
...
P.S Usage can be different based upon the logic of components, just giving an hint how we can patterns to serve our purpose.
Hope it helps.
I've been struggling with a very odd bug(?) with regards to importing an API module into a nested component in a Vue app.
This is the simplest I could reduce the issue down to.
https://codesandbox.io/s/rough-tree-fqj7o
Essentially, the DogsCreate component renders the CreateDogsModal, which is importing the dogs module from the API directory.
As you can see, the codesandbox errors out even on the base URL with the error Cannot read property 'default' of undefined. If running this code locally not on codesandbox, the base URL renders ok, but if you go to /dogs/create, the error then becomes Failed to resolve component: CreateDogsModal.
The things I've found that fix this are:
Commenting out the API import statement in CreateDogsModal (not an option for us, we need to be able to create and import API modules)
Commenting out the TopNav component in main.js (...also not an option for us)
Importing the TopNav component in App.vue with a relative import or #/components/TopNav.vue works fine, but strangely importing CreateDogsModal and CreateTemplate in DogsCreate.vue with a relative import or #/components/[component-name].vue does not. Also, the latter would be somewhat acceptable as a long-term solution, but I'd prefer the #/components shorthand and that still leaves the root cause undetermined.
I'm using the default vue-cli webpack configuration and have checked via vue inspect that the alias seems to be set properly.
I've been spinning my wheels for a week trying to figure this out and just...cannot. Does anyone have any ideas for what may be happening?
It seems like a race condition in Webpack, using parallel builds, but I'm honestly not sure. I can see CreateDogsModal being pulled in from two places, starting from main.js:
'main.js'
- import 'App.vue'
- import '#/components/index.js'
- import and export 'CreateDogsModal.vue'
- import 'router/index.js'
- import '#/views/Dogs/DogsCreate.vue'
- import '#/components/index.js'
- import and export 'CreateDogsModal.vue'
One workaround is to remove the race by making the CreateDogsModal an async component in DogsCreate:
// DogsCreate.vue
import { defineAsyncComponent } from "vue";
import { CreateTemplate } from "#/components";
export default {
name: "DogsCreate",
components: {
CreateTemplate,
CreateDogsModal: defineAsyncComponent(() => import("#/components/CreateDogsModal.vue")),
},
};
demo
I have a scenario with 2 components:
App
People
I want to test if People gets rendered 10 times inside App. So, I'm trying to test that using Jest. So far, I did this on my src/App.test.js:
import React, { Component } from "react";
import People from "./components/People";
import App from './App';
test('Total people = 10', () => {
expect(App).find(People).toHaveLength(10);
});
But I get a message saying:
TypeError: expect(...).find is not a function.
How can I test how many times a component gets rendered inside another component using React and Jest? Can anyone help me?
For testing react components first you need to render them, there are some tools for doing that, but since your reasoning in this test is to check how many times a component has been rendered inside another component, enzyme does a good job with its shallow method.
import React from "react";
import App from "./App";
import People from "./components/People";
import { shallow } from "enzyme";
it("Total people = 10", () => {
const wrapper = shallow(<App />);
expect(wrapper.find(People)).toHaveLength(10);
});
You'll need to set up enzyme in your project first, read the docs for more details.
The current trend in testing is to check for the things the user actually sees in the page, so most people is using react-testing-library, It'll be good for you to check it out
If you ever switch to react-testing-library, you might write the test something like this:
import React, { Component } from "react";
import App from './App';
import {render} from "#testing-library/react";
test('Total people = 10', async () => {
const { getAllByText } = await render(<App />);
expect(getAllByText('string_in_People')).toHaveLength(10);
});
Basically you'd use one of the library's built-in getAllBy... query methods to query for all instances of an element that appears exactly once in each instance of your <People /> component. The resulting set's length will equal the number of <People /> instances on the page.
What is the major benefit of writing
import React, { Component } from 'react';
class Link extends Component {
...
}
instead of
import React from 'react';
class Link extends React.Component {
...
}
when it comes to react 15.4.x??
In my perspective and in my case (correct me if I am wrong) it does not matter at all since:
I am using a webpack2 for making my bundles;
I use code splitting to split my app code from vendor code;
I use webpack.optimize.CommonsChunkPlugin plugin with minChunks: Infinity setting to make sure that all vendor code is included only once.
From understanding how ES6 imports work I understand that by using named import of {Component} I state that I want to use only Component component in my code, which looks.. cleaner.
But since whole React package is still used in the app, I can create my classes with extension from React.Component instead of just Component and in result webpack will still produce the same amount of code and my bundle size will be the same in both cases.
Am I correct?
There is no difference, React.Component is the same object as Component, the second way is more eloquent in my opinion, because it really explains that you are using the Component object from the React library.
The first one seems to refer a member,
but, it comes from the pre modules era of javascript, where everything had to be attached to the exported global namespace (just to avoid global namespace pollution).
something that could be under the hood:
// this should be assumed as an example only.
class React { ... }
class Component { ... }
React.Component = Component;
// ES6
export {Component}
export default React;
// ES5
window.React = React;
Note: as someone said, you also need to import React because JSX needs to have it on scope, but, if you want to avoid it, you can expose React globally (window.React = React)
This import statement:
import React, { Component } from 'react';
is really doing two things. It imports the default export, under the name React (which is just a convention, you could call it what you want). It also imports a named export, Component.
The reason that the default React is imported is actually to make JSX work. When your JSX code is transpiled, then it substitutes <div> for React.DOM.div(), so React must exist otherwise things break!
Importing both things separately means that your JSX works but you get to write Component instead of React.Component in your code.
When you do import anything from "react", then the whole file is going to get included either way - any attempt to reduce the bundle size (e.g. Dead Code Elimination, Tree Shaking) is an additional, separate step, which doesn't depend on your import statements but the parts of the code that you use.
In the case of this library, the sane thing happens: the child Component of the default export refers to the same thing as the named export Component.
However, bear in mind that this isn't guaranteed to be the case! If the React library code contained the following:
export default {
Component: "foo"
};
export const Component = "bar";
Then React.Component === "foo" and Component === "bar".
Currently a typical component will look like the below code. Note that using the paths to the file has become problematic and ugly. Moving a file causes massive issues with updating paths across multiple components.
This truly takes away from the component based experience when a path change can break everything and cause mass find and replace of paths.
In an ideal world the displayName would be the import reference and searched for within the directory.
'use strict';
//libs
import React from 'react';
//components
import TopFeatures from '../../headphones/subcomponents/top-features';
import Prices from './prices';
import Image from '../../layout/image';
import InlineRatingElement from '../../reviews/rating';
//helpers
import { getImageUrl } from '../../helpers/app/image';
import { initiateInlineRatings } from '../../helpers/app/inline-ratings';
export default class HDOverview extends React.Component {
displayName = 'HDOverview'
static propTypes = {
vendor: React.PropTypes.string.isRequired
}
constructor(props) {
super(props);
}
render() {
return (
<div>
JSX
</div>
);
}
}
I am looking to do something like this:
import TopFeatures from 'TopFeatures';//TopFeatures is the displayName
import Prices from 'Prices'; //Prices is the displayName etc.
import Image from 'Image';
import InlineRatingElement from 'InlineRatingElement';
//helpers
import { getImageUrl } from 'ImageHelper';
import { initiateInlineRatings } from 'InlineRatingHelper';
Webpack has a great tutorial on resolve aliases here: http://xabikos.com/javascript%20module%20bundler/javascript%20dependencies%20management/2015/10/03/webpack-aliases-and-relative-paths.html
However this insinuates that the path to the component would need to be logged in one place - in an ideal world there would be a way to dynamically check paths / directories to find the displayName that matches. Note that we have 200 components, so manually creating that list is do-able but sizable.
Having looked around I have seen people using
require("components!/layout/image")
however we would like to stick to the import technique and not go back to require.
Any suggestions or advice are greatly appreciated.
I think that this is, unfortunately, a limitation of node, npm.
There are workarounds to get absolute/mapped paths to work in npm but all of these have drawbacks: https://gist.github.com/branneman/8048520
Another option is individual npm packages for each component, but this adds a lot of overhead.