React component name must start with capital letter when using hooks - reactjs

I'm trying to build my web-site with React.
I've learned that it's a good practice to name functional components starting with a capital letter, but presentational components name should start with a lowercase letter.
I try to follow this rule, but when I import any hook to presentational component named starting with lowercase, React says "Failed to compile".
Here is the message
Line 10:26: React Hook "useContext" is called in function "newCoring" which is neither a React function component or a custom React Hook function react-hooks/rules-of-hooks
I know that renaming component will help, but still wonder why it's "a good practice" to name presentational components this way when it does not work with React hooks?
Here is my component:
import React, {useContext} from 'react'
import InputComponent from '../Interface Components/InputComponent'
import SelectComponent from '../Interface Components/SelectComponent'
import AddToCart from '../Interface Components/AddToCart'
import DrawButton from '../Interface Components/DrawButton'
import Signs from '../Interface Components/Signs'
import Cog from '../Interface Components/Cog'
import InputContext from '../../context/input-context'
const newCoring = () => {
const inputContext = useContext(InputContext);
return (
<div className="first-line">
<Signs/>
<InputComponent id="width" default="500">Width:</InputComponent>
<InputComponent id="height" default="500">Height:</InputComponent>
<InputComponent id="depth" default="250">Depth:</InputComponent>
<SelectComponent id="diameter" default="152" values={inputContext.diameters}>Diameter:</SelectComponent>}
<Cog/>
<AddToCart/>
<DrawButton/>
</div>
);
}
export default newCoring;

but presentational components name should start with a lowercase letter
They aren't, User-Defined Components Must Be Capitalized
When an element type starts with a lowercase letter, it refers to a built-in component like <div> or <span> and results in a string 'div' or 'span' passed to React.createElement. Types that start with a capital letter like <Foo /> compile to React.createElement(Foo) and correspond to a component defined or imported in your JavaScript file.

Related

Is import case insensitive in React?

I have been following a React course online. When the course talked about hooks in React, I saw this sample code:
import AlertContext from '../../context/alert/alertContext'
But when I went to alertContext.js module, I noticed the default exported module object is alertContext, the object name started with "a" instead of "A". The code is like export default alertContext.
Does it mean import is case insensitive?
When you have a default export on a custom component, you can import it with any name you like.
default export can have any name inside it and can be imported with any other name on other components.
But its important to import the custom component with UpperCase as React understands uppercase as a custom component and lower case as a native component.
Native Components => <div> , <p>, <input> etc
Custom Components => <AlertContext>
Example:
/*customComponent.js*/
const customComponent = () => <div> I am Custom </div>
export default customComponent;
/*App.js*/
import MyCustomComponent from './customComponent'
const App = () => <MyCustomComponent />
export default App;

Sending a React.FunctionComponent<React.SVGProps<SVGSVGElement>> as a prop to another component

I'm attempting to import a React functionComponent from an SVG and then send that to another component as a prop to render that svg. With the setup below, this compiles fine, but eventually crashes when trying to render the svg in browser with:
Error: Objects are not valid as a React child (found: object with keys {$$typeof, render}). If you meant to render a collection of children, use an array instead.
Classes below are simplified. But the gist of what I'm trying to do is:
In overlay.tsx:
import { ReactComponent as icon } from "/icon.svg";
import CustomItem from "/customItem";
const Overlay: React.FC<OverlayProps> = () => {
return (
<div>
<CustomItem icon={icon}/>
</div>
);
export default Overlay;
}
and in customItem.tsx:
import React from "react";
export interface CustomItemProps {
icon: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
}
const CustomItem: React.FC<CustomItemProps> = ({icon}) => {
return (
<div>
{icon}
</div>
);
};
export default ApplicationsDropdownItem;
I assume my problem is somewhere around the syntax of {icon}, but I can not for the life of me find out what I'm suppose to use instead.
Answer
The icon you are importing is a component, therefore it must be called to render the JSX.
<Icon {...props}/> (correct) or {Icon(props)} (not recomended)
Since it is a component, you should also name it Icon and not icon.
Take a look at this blog post that explains SVGR.
TL;DR - Best approach for rendering components
A. Call the component in your render method with component syntax <MyComponent/> not MyComponent().
B. Instantiate your component as a variable, and pass that to your render method's JSX block.
More info
#DustInCompetent brought to light the issue of calling a component as a function inside a JSX block.
As explained here and here, that will lead to react not registering a components hooks and lead to state and other problems.
If you are implementing a High Level Component (HOC), then you should not call a component within the render method (return statement in functional components), as this leads to problems for similar registration issues of the component.
import React from "react";
import { ReactComponent as SampleIcon } from "/sample_icon.svg";
export interface CustomItemProps {
Icon: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
}
const CustomItem: React.FC<CustomItemProps> = (props) => {
const Temp = props.Icon as React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
return (
<div>
<Temp/>
</div>
);
};
<CustomItem Icon={SampleIcon}/>
I think you should use <Icon /> instead of {icon} because it's a component.

Problem importing stateless function is react

I am very new to react and having a bizarre problem. I have defined a stateless function and when i want to try to import it in my main component it is not loading the function. i am guessing there is a naming convention that i dont know of. npm start does not give any error so I am assuming the code is compiling ok.
My stateless component is below
import React from 'react';
const AppHeader = () => {
return(
<div class="jumbotron text-center">
<h1>Map Search</h1>
<p>Searching map for nearest matches from account</p>
</div>
);
}
export default AppHeader;
below does not work,
import React from 'react';
import './App.css';
import appHeader from './UI/appHeader';
class App extends React.Component {
render(){
return (
<div className="App">
<appHeader/>
</div>
);
}
}
export default App;
VS code lint says
appHeader is declared but its value is never used.
However below does work,
import React from 'react';
import './App.css';
import KKK from './UI/appHeader';
class App extends React.Component {
render(){
return (
<div className="App">
<KKK/>
</div>
);
}
}
export default App;
VS code lint does not show the error anymore also the app is working as expected. As you can see i only changed the name of the appHeader component to KKK. can someone point out what am i doing wrong and may be provide any documentation around this.
You need to capitalize appHeader to be AppHeader in order for React to understand that this is a custom component and not a built in html component. Components that start with lowercase are assumed to be built in HTML elements.
Check out this answer: ReactJS component names must begin with capital letters?
And from the React docs:
User-Defined Components Must Be Capitalized
When an element type starts with a lowercase letter, it refers to a built-in component like or and results in a string 'div' or 'span' passed to React.createElement. Types that start with a capital letter like compile to React.createElement(Foo) and correspond to a component defined or imported in your JavaScript file.
We recommend naming components with a capital letter. If you do have a component that starts with a lowercase letter, assign it to a capitalized variable before using it in JSX.

React.js "Empty Object" issue when rendering the Container component into App component?

I am getting the "Empty object" in React console when rendering the Container component into the App component.
1,user-list.js: This is my container component.
import React , {Component} from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
class userList extends Component {
render() {
return (
<div>
<h1>sample</h1>
</div>
);
}
}
export default userList;
2,App.js: This is my App file this is where I am trying to display the "userList " but "sample" is not displayed in the browser.
import React from 'react';
import userList from '../containers/user-list';
require('../../scss/style.scss');
const App = () => {
return (
<div>
<h2>User List</h2>
<userList />
<hr />
<h2>User Details</h2>
</div>
);
}
export default App;
Please correct me if I am missing something?
I solve your problem with only one single small step: Changing the userList into UserList.
import React from 'react';
import UserList from '../containers/user-list';
const App = () => {
return (
<div>
<h2>User List</h2>
<UserList />
<hr />
<h2>User Details</h2>
</div>
);
};
export default App;
The reason is "React treats components starting with lowercase letters as DOM tags". From the Official React Document:
React treats components starting with lowercase letters as DOM tags. For example, represents an HTML div tag, but represents a component and requires Welcome to be in scope.
The reason behind this convention:
User-Defined Components Must Be Capitalized
When an element type starts with a lowercase letter, it refers to a built-in component like or and results in a string 'div' or 'span' passed to React.createElement. Types that start with a capital letter like compile to React.createElement(Foo) and correspond to a component defined or imported in your JavaScript file.
We recommend naming components with a capital letter. If you do have a
component that starts with a lowercase letter, assign it to a
capitalized variable before using it in JSX.
Try changing userList to UserList, with capital U.
In JSX, lower-case tag names are considered to be HTML tags. However, lower-case tag names with a dot (property accessor) aren't.
So the problem is your userList begins with small u. You should change it while exporting as well as wherever you are using it. Look at the below code to see where it needs to be corrected.
class UserList extends Component
export default UserList;
import UserList from '../containers/user-list';
<UserList />

where should I dispatch my redux

I am learning react and redux, and I just have a small question about where should I dispatch and share my redux store to react components, should I share and dispatch my store in whatever components that need the store or I should share and dispatch my store in one main component and share that values as props to order components?
for example I have these three components and I have my states stored in one FlashCard component and share that states to Cardlist component using props and then the CardList component will send that props to Card component. is it the right thing to do? and also in card component I use dispatch because it seem more convenient, but should I use dispatch in my main component FlashCard as well and pass the change to Card component? thanks for your help.
import React from 'react';
import CardList from './cardList';
import {connect} from 'react-redux';
const FlashCard =(props)=>{
return (
<div>
<CardList
cards={props.cards}
/>
</div>
)}
const mapStateToProps=(state)=>({
cards:state.cards
})
export default connect(mapStateToProps,null)(FlashCard)
and
import React from 'react';
import Card from './card';
const CardList =(props)=>{
const card=props.cards.map((c,i)=>(
<Card
key={i}
card={c}
/>
))
return(
<div>{card}</div>
)}
export default CardList
and a Card component to render all the cards
import React from 'react';
import {connect} from 'react-redux';
import { showCardInfo, hideCardInfo } from '../redux/flashCardRedux';
const Card =(props)=>{
const onCardClick=()=>{
console.log(props.card.id)
}
return (
<div>
{props.card.showInfo?
<div
onClick={()=>props.dispatch(hideCardInfo(props.card.id))}
>{props.card.name}</div>
:
<div
className='card'
onClick={()=>props.dispatch(showCardInfo(props.card.id))}
>
<div className='img'>
<img src={props.card.img}/>
<h3>{props.card.name}</h3>
</div>
</div>}
</div>
)}
export default connect()(Card)
For me, I have found it best practice to only refer to dispatch in the main component and only pass in what the child components require as properties. This not only means that you are not passing dispatch around to everything, but also allows for unit testing of the smaller components if required.
It also keeps the smaller components much "lighter" in that they only have what they need, and can easily then be rendered in other areas of your app.
In the future, if you ever wanted to swap out Redux for something similar, it means you are then only having to edit code in the main component rather than everywhere in your system.
Its always recommended to use dispatch in parent component because
child is also part of parent but as per requirement you can shift.
as you have parent to child connection either you can connect in
parent and pass data as `props` or either you can take out in child
component itself, it depend upon how complex your parent and
child.however for smaller component always use as props else go for
component wise connect.
for more info [follow this](https://reactjs.org/)

Resources