Let's look at scenario where we have blogs in each page as we did it in Home page. Then we need to repeat the code block in every page.
How to do it in a more better way.
we can make that bit of template as resusable component. eg: blog list component
{blogs.map(((blog) => (
<div className='blog-preview' key={blog.id}>
<h2>{blog.title}</h2>
<p>Written by {blog.author}</p>
</div>
)))}
So if need to use that part in a category, tag or in any place we can just drop our component 'blog-list'. We don't need to repeat this total boiler plate code.
We use 'props'
with this template or component will be same, but data will be different. This helps to reuse.
1. create blog list component to hold the logic
2. create file 'BlogList.js' and create component BlogList
const BlogList = () => {
return ();
}
export default BlogList;
3. Inside return copy paste the template we a re going to reuse.
4. Before that let's create a div , className=blog-list
const BlogList = () => {
return (
<div className='blog-list'>
{blogs.map(((blog) => (
<div className='blog-preview' key={blog.id}>
<h2>{blog.title}</h2>
<p>Written by {blog.author}</p>
</div>
)))}
</div>
);
}
5. Now inside home.js , we can simply use <BlogList />
return (
<div className="home">
<BlogList />
</div>
);
6. Now you get an error
'blogs' is not defined no-undef
7. Because blogs data is not defined inside BlogList, we cannot use data defined inside another component.
8. How to solve ? There are few solutions.
8.1 Define data inside BlogList instead of Home
8.2 Use Props -> we pass this data from Home component into the BlogList component.
9. We use second option props for three reasons
a. make BlogList component more resusable
b. We can still use data in the Home component, if needed inside Home component
c. Most important -> How to use props
10. Props is a way to pass data from a parent component to child component
11. Here Home is the parent and BlogList is the Child component
12. we are passing 'blogs' data into BlogList component
13. To do that, we create a property inside the <BlogList /> tag. You can call any name. Let's call 'blogs' as it's what we are passing.
<BlogList blogs= />
14. So this going to be a dynamic value, So curly braces.
<BlogList blogs={} />
15. value is 'blogs'. defined in top of the Home component.
<div className="home">
<BlogList blogs={blogs} />
</div>
16. Now this is a prop. Now you will see an error
src\component\BlogList.js
Line 4:14: 'blogs' is not defined no-undef
17. This is cause of the next step, we are now going to use in BlogList. give tis as a parameter to BlogList
const BlogList = (blogs) => {
return (
<div className='blog-list'>
{blogs.map(((blog) => (
<div className='blog-preview' key={blog.id}>
<h2>{blog.title}</h2>
<p>Written by {blog.author}</p>
</div>
)))}
</div>
);
}
18. Now your error will disapear
19. Now we have another error
TypeError: blogs.map is not a function
20. getting an error
Failed to compile
./src/component/BlogList.js
SyntaxError: C:\Project\Project\Training\React\NetNinja\dojo-blog\src\component\BlogList.js: Identifier 'blogs' has already been declared. (1:18)
This is cause, i used 'blogs' instead of 'props' in BlogList(props)
const BlogList = (blogs) => {
const blogs = this.props.blogs;
return (
<div className='blog-list'>
{blogs.map(((blog) => (
<div className='blog-preview' key={blog.id}>
<h2>{blog.title}</h2>
<p>Written by {blog.author}</p>
</div>
)))}
</div>
);
}
--------------------------------------
corrected code is
----------------------
const BlogList = (props) => {
const blogs = this.props.blogs;
return (
<div className='blog-list'>
{blogs.map(((blog) => (
<div className='blog-preview' key={blog.id}>
<h2>{blog.title}</h2>
<p>Written by {blog.author}</p>
</div>
)))}
</div>
);
}
export default BlogList;
--------------------
21. But still get an error
TypeError: Cannot read properties of undefined (reading 'props')
BlogList
C:/Project/....../src/component/BlogList.js:2
1 | const BlogList = (props) => {
> 2 | const blogs = this.props.blogs;
3 | return (
4 | <div className='blog-list'>
5 | {blogs.map(((blog) => (
22. Reason for using 'this' keyword when accessing props
const blogs = this.props.blogs;
23. remove 'this' and you will see page in the browser
24. Let's console out props and blogs
console.log(props,blogs);
25. you can see all the properties and blogs list.
Now we can pass multiple props
---------------------------
26. eg:title , it can be dynamic value, but here we just pass a string in Home.js
27. <BlogList blogs={blogs} title="All Blogs"/> in Home.js
28. Now we can access this from BlogList and let's use in h2 tag and out put.
-----------------------------------------------------
const BlogList = (props) => {
const blogs = props.blogs;
const title = props.title;
return (
<div className='blog-list'>
<h2>{title}</h2>
{blogs.map(((blog) => (
<div className='blog-preview' key={blog.id}>
<h2>{blog.title}</h2>
<p>Written by {blog.author}</p>
</div>
)))}
</div>
);
}
--------------------------------------------------
Further we can destructure 'props'
then we don't need const variables and can use straight away.
Code will looks like
---------------------------------------------------
const BlogList = ({blogs, title}) => {
// const blogs = props.blogs;
// const title = props.title;
return (
<div className='blog-list'>
<h2>{title}</h2>
{blogs.map(((blog) => (
<div className='blog-preview' key={blog.id}>
<h2>{blog.title}</h2>
<p>Written by {blog.author}</p>
</div>
)))}
</div>
);
}
----------------------------------------------------
you can play with code and check what happens after changing name of the props and variables.
Yu can see , it will still work without any issues.
const BlogList = (props1) => {
const blogs = props1.blogs;
const title = props1.title;
return (
<div className='blog-list'>
<h2>{title}</h2>
{blogs.map(((blog) => (
<div className='blog-preview' key={blog.id}>
<h2>{blog.title}</h2>
<p>Written by {blog.author}</p>
</div>
)))}
</div>
);
}