I'm working with React JS (hooks) for recently. For a project, I need to split many strings in different divs. So, I created a function to this, that saves me some time! My actual question is : Should I create a custom Hook instead of my function ?
Of course, the actual code works, but as a beginner, I don't know if my way is clean. I need feedbacks cause my main goal to write the best and clear code as possible.
// Splitting Texts
const splitText = str => {
return (
<div>
{str.split(' ').map((item, index) => {
return (
<div key={index}>
{item}
</div>
);
})}
</div>
);
};
// Main App
export default function App() {
const name = splitText('Lucie Bachman');
const description = splitText('Hey, this is my first post on StackOverflow!');
return (
<div className="App">
<h1>{name}</h1>
<h2>{description}</h2>
</div>
);
}
Expected results :
<h1>
<div>
<div>Lucie</div>
<div>Bachman</div>
</div>
</h1>
I'm super excited to have joined the community!
Thanks to you, and take care.
Lucie Bachman
A custom hook is something that uses out of the box react hooks to actually provide a logic and return data.
If the function returns JSX, its actually just a function or can be used as a functional component
Since you only want to split string once you can convert it into a component and use React.memo to optimize rendering
// Splitting Texts
const SplitText = React.memo(({str}) => {
return (
<div>
{str.split(' ').map((item, index) => {
return (
<div key={index}>
{item}
</div>
);
})}
</div>
);
});
// Main App
export default function App() {
return (
<div className="App">
<h1><SplitText str={'Lucie Bachman'} /></h1>
<h2><SplitText str={'Hey, this is my first post on StackOverflow!''} /></h2>
</div>
);
}
Related
I am trying to create a grid layout of video components but my IDE gives me a warning saying
Expression statement is not assignment or call
import React, {Fragment} from 'react';
import VideoClip from "../Video/VideoClip";
function SubjectView(props) {
let ids = ["RfKHsvF69VdjdMu6bdugsyRcjYpQXrpKd6iZHeEknCkY00",
"RfKHsvF69VdjdMu6bdugsyRcjYpQXrpKd2ipHeEknCkY00",
"RfKHsvF69Vdjdiu6bdugsyRcjYpQXrpKd2iZHeEknCkY00"
];
return (
<Fragment>
<div className="columns-3" >
{ids.map((id)=>{
<VideoClip id={id}/>
console.log(id)
})}
</div>
</Fragment>
);
}
export default SubjectView;
I see the IDs printed in the console but nothing renders.
The video component looks like
function VideoClip() {
let { id } = useParams();
return (
<div className="container mx-auto px-4">
<MuxPlayer
streamType="on-demand"
playbackId={id}
metadata={{
video_id: "video-id-54321",
video_title: "Test video title",
viewer_user_id: "user-id-007",
}}
/>
</div>
);
}
export default VideoClip
I am wondering if I am trying to create the components incorrectly. Is there a best practice when trying to achieve this?
You're not returning any value from ids.map
<>
<div className="columns-3" >
{ids.map((id)=><VideoClip id={id}/>)}
</div>
</>
One issue is you are not returning <VideoClip id={id}/> in map function in jsx. Also, if map is used - key needs to be set
return (
<Fragment>
<div className="columns-3">
{ids.map((id) => {
console.log(id);
return <VideoClip key={id} id={id} />;
})}
</div>
</Fragment>
);
Next issue is about VideoClip component parameter. Id needs to be extracted in that way in case it is passed as an attribute. Also, memoize the objects that you are passing down to a components. Metadata here, for example.
function VideoClip({ id }) {
const metadata = useMemo(() => {
return {
video_id: "video-id-54321",
video_title: "Test video title",
viewer_user_id: "user-id-007"
};
}, []);
return (
<div className="container mx-auto px-4">
<MuxPlayer streamType="on-demand" playbackId={id} metadata={metadata} />
</div>
);
}
Last thing - wrap your array in useMemo so this array will not cause crazy rerenders.
const ids = useMemo(
() => [
"RfKHsvF69VdjdMu6bdugsyRcjYpQXrpKd6iZHeEknCkY00",
"RfKHsvF69VdjdMu6bdugsyRcjYpQXrpKd2ipHeEknCkY00",
"RfKHsvF69Vdjdiu6bdugsyRcjYpQXrpKd2iZHeEknCkY00"
],
[]
);
Note: you will see x2 logs in the console in the Codesandbox due to <StrictMode> is set.
import React from 'react'
import CoinItem from './CoinItem'
const Coins = (props) => {
return (
<div className='container'>
<div>
<div className='heading'>
<p>#</p>
<p className='coin-name'>Coins</p>
<p>Price</p>
<p>24h</p>
<p className = 'hide-mobile'>Volume</p>
<p className = 'hide-mobile'>Market Cap</p>
</div>
{props.coins.map(coins => {
return (
<CoinItem coins={coins} key={coins.id} />
)
})}
</div>
</div>
)
}
export default Coins
With this code, my app won't render and I get the error, "Uncaught TypeError: props.coins.map is not a function." However, it directs me to the line where I create a div with the class name of the heading.
However, when I comment out:
{props.coins.map(coins => {
return (
<CoinItem coins={coins} key={coins.id} />
)
})}
and uncomment it again, my app renders perfectly with the API working, but once again, when I refresh, the app de-renders.
How do I fix this?
CodeSandbox link: https://codesandbox.io/s/busy-cloud-pcfne0?file=/src/components/Coins.js:409-512
A few things you can do is:
Ensure that the "coins" prop exists.
If it exists, make sure it is an Array and not an Object. You cannot use .map() on an Object. it is an Array method.
To avoid the code running a .map() when coins is null/undefined, add a ? after props.coins so that the .map() runs only if coins is defined.
{props.coins?.map(coin => { /*YOUR CODE HERE*/ })
I use axios to get the data from the server and store the received data into the array setCountries. This part works.
Code in codesandbox
Then, I simply want to render the whole list of country names contained on the array using map.
I am making some mistake there, because I get the error
TypeError: setCountries.map is not a function
The error comes from this part of the code.
Where is the error coming from?
const [countries, setCountries] = useState([])
const showCountries = () => {
return (
<div>
<ul>
{setCountries.map((country) =>
<p key={country.alpha2Code}>{country.name}</p>
)}
</ul>
</div>
)
}
return (
<div>
<div>
<h1>Countries</h1>
{showCountries()}
</div>
</div>
);
}
export default App;
You're using function setCountries instead of array countries
Corrected:
<ul>
{countries.length > 0 && countries.map((country) =>
<p key={country.alpha2Code}>{country.name}</p>
)}
</ul>
Also use null checks to avoid other issues
setCountries is a function for setting the country's state. It does not have the map function.
The solution here will be to use countries.map instead:
const showCountries = () => {
return (
<div>
<ul>
{countries.map((country) =>
<p key={country.alpha2Code}>{country.name}</p>
)}
</ul>
</div>
)
}
setCountries is a function and that's why you can't use a map. If you try the code I wrote below, your problem will be resolved.
{countries.map((country) =>
<p key={country.alpha2Code}>{country.name}</p>
)}
Within the same file, I'm having an element (or group of elements) that I want to convert to something reusable. But because it is very small, I don't want to create a new file.
Ex.
// Article.js
const Article = props => {
const { name, tel } = props
return (
<div>
<section>
<p>Content A</p>
<small>Contact {name} now, via {tel}</small>
</section>
<small>Contact {name} now, via {tel}</small>
<div>
Having questions?
<small>Contact {name} now, via {tel}</small>
</div>
</div>
)
}
As you can see here, <small>Contact {name} now, via {tel}</small> is being used many times in Article component. So I want to convert it to something reusable, either a Component or just a JSX element.
The key points are:
I do not want to create a new file, because it will never being used by other components.
It needs to display content depending on name and tel variables.
It does not need to be flexible, the name and tel will always be the same as from Article props.
So I tried to achieve my goal with:
Option 1: Separated React Component (in the same file)
// Article.js
const Contact = props => {
const { name, tel } = props
return <small>Contact {name} now, via {tel}</small>
}
const Article = props => {
const { name, tel } = props
return (
<div>
<section>
<p>Content A</p>
<Contact name={name} tel={tel}/>
</section>
<Contact name={name} tel={tel}/>
<div>
Having questions?
<Contact name={name} tel={tel}/>
</div>
</div>
)
}
But from my key point number 3, I find this option redundant because I have no need to make Contact accepting props. Since this component will always display the same name and tel as from Article. So I come up with Option 2.
Option 2: React Component in React Component
// Article.js
const Article = props => {
const { name, tel } = props
const Contact = () => (
<small>Contact {name} now, via {tel}</small>
)
return (
<div>
<section>
<p>Content A</p>
<Contact />
</section>
<Contact />
<div>
Having questions?
<Contact />
</div>
</div>
)
}
The Contact component is shorter because it accepts no props. But the question is if it does not accepting props, shouldn't I just write it as a JSX element? So I come up with Option 3.
Option 3: JSX Element in React Component
// Article.js
const Article = props => {
const { name, tel } = props
const renderContact = <small>Contact {name} now, via {tel}</small>
return (
<div>
<section>
<p>Content A</p>
{renderContact}
</section>
{renderContact}
<div>
Having questions?
{renderContact}
</div>
</div>
)
}
This one I don't know how to name it properly (renderContact, contactElement, or contact?) because I have not seen it much.
Every option is working, but I want to know the differences between these styles,
Performance - how does each one work / how does it affect the perf?
Pros and Cons
Limitations - is there anything to worry when using it?
Popularities - what is the standard way of writing React?
In this situation we write a reusable function usually called renderer
const Article = props => {
const { name, tel } = props
const renderer=(name,tel)=>{
return (
<small>Contact {name} now, via {tel}</small>
)
}
return (
<div>
<section>
<p>Content A</p>
{renderer(name,tel)}
</section>
</div>
</div>
)
}
I would like to insert advertisement block (such as Google Adsense) inside of items list. I am using the react-redux & react-connect. Even if I need to refresh the feed and rerender, I would like to run the render of ad-block div only one time. Is there any way we can do this?
render(){
const { feed } = this.props;
return(
<div>
<div class="ad-block"><!-- Need To Render one time --></div>
<div class="items">
{_.map(feed.data, item => {
return <div class="item">.......</div>
})}
</div>
<div class="ad-block"><!-- Need To Render one time --></div>
);
}
How about to split it in 3 components?
export const Something = () => (
<>
<AdBlock>
<Feed>
<AdBLock>
<>
);
And connect Feed separately through Redux.