Making reusable component for array data in reactjs - reactjs

I want to make a footer component in react with a heading and several links under it like in the image.
Also I want to pass only an array for the links like the following.
const FooterLinksData = [
{
link1: "Insolvers",
link2: "How it works?",
link3: "I'm looking for job",
link4: "I'm looking to hire",
},
{
link1: "Features",
link2: "Pricing",
link3: "Schedule a Demo",
},
];
My code:
return (
<>
<li>
<a href="/" className="footer_link">
{props.data[`link${props.num + 1}`]}
</a>
</li>
// I have written this li tag for times in my code
// props.data is the array I passed using the parent
// props.num is the number (0 in this case) to get link1 from
// the object
</>
);
My problem is that first obj under the array has 4 items while the second one only have 3. Is there any way to make a reusable component for it?

You can add the title inside the json and use it to bracke. Something like
const FooterLinksData = [
{
"title":"some title",
"links":[
"Insolvers",
"How it works"
]
},
{
"title":"some other title",
"links":[
"other Insolvers",
"other How it works"
}]
];
so then you will do something like:
FooterLinksData.map(({title, links}) => ({
<div>
<div>{title}</div>
<ul>{links.map(link => <li>{link}</li>)}</ul>
</div>
})
})

If you ask this question, I assume you use FooterLinksData[x].link1, FooterLinksData[x].link2, FooterLinksData[x].link3 ..... to display your links.
You could change your code to use the map() function instead, not having to deal with a fixed number of links.
Can't really help with code since you didn't posted how you render your links.

Related

How to go through a JSON with buttons in ReactJS

I want to move through the contents of a JSON file with buttons.
This is the basic structure of my JSON:
[
{
"page": "1",
"required": "true",
"question": "lorem ipsum",
},
{
"page": "2",
"required": "true",
"question": "lorem ipsum dolor",
}
]
I'm building a multi-step form and I want to get the questions from this JSON. Is there any way for me to have a Next button, that moves one index forward in the JSON file, and displays the info in that index? The page identifier is unique to every object.
I'm new to React, so any explanations will be appreciated!
In my opinion, in order to iterate through the questions of your JSON, you'll first need to parse it by using JSON.parse() (documentation).
So per exemple, let's say your component looks like this :
function Form() {
[questions, setQuestions] = JSON.parse(your_json);
[currentQuestion, setCurrentQuestion] = 0;
function nextQuestion {
setCurrentQuestion = currentQuestion + 1;
}
return (
<div>
<label>{{ questions[currentQuestion].question }}</label>
<input type="text" />
<button onclick={ nextQuestion }>Next Question</button>
</div>
);
}
By doing this, you'll parse the JSON text, changing it to an object format, and make you being able to call any value. Then we have a counter and we will be able to change it's value by calling setCurrentQuestion. The method nextQuestion() does exactly this.
Then, in our JSX, we can display the question based on it's position in the JSON, and go to the next question by clicking the button. React will react to the value change by itself and then, change the question value automatically.
I hope that my answer help while being clear enough and I didn't do any mistake typing it ^^

How to get prevState value or all object in useState in React?

In trek_tours i have an array and inside array i have define object and inside object their are some array and the format is in below
treks_tours[
{
title: "Everest Base Camp",
Prices: [
"Price Start from 300 per/person",
"Note - if you are number of people then we can make you good discount!",
],
},{
title: "Jungle Safare & Knowing Villager Life Style",
Prices: [
"Price Start from 1650 per/person",
"Note - if you are number of people then we can make you good discount!",
],
}
]
In this section i want to see the title and price name of differrent objects but i got repeted title same time. anyone please help me!!!
const [tripPrice, setTripPrice] = useState({});
const price = () => {
treks_tours.map((price) =>
setTripPrice((prevState) => ({
...prevState,
price: price.Prices[0].split(" ")[3],
title: price.title,
}))
);
};
console.log(tripPrice);
useEffect(() => {
price();
}, []);
Output
So from that array of objects, you want to individually console.log() all of them?
If so you want to individually console.log() all the objects all you have to do is:
trek_tours.forEach((tour) => {
console.log(tour);
})
And then it will console.log() every object in array. Is that what you mean?
If all you want to do is setTripPrice to array trek_tours
then all to do is to say setTripPrice(trek_tours) - no need of anything else.
Then if you console.log(tripPrice) you get all the objects inside the array. If this is not what you mean please provide a codesandbox link
{treks_tours.slice(0, 3).map((trek_tour, key) => {
<p className="text-lg text-black">
Starting from : $ {trek_tour.Prices[0].split(" ")[3]}
</p>
);
})}

vue: access a specific array from an object inside an array

I want to show only one of the questions array in a single page, depending on which category the user picks.
faqData = [
{
name: "first-category",
questions: [
{
id: 1,
question: "First question?",
answer: "First Answer"
},
{
id: 2,
question: "Second question?",
answer: "blablablabla"
}
]
},
{
name: "second-category",
questions: [
{
id: 1,
question: "First question?",
answer: "First Answer"
},
{
id: 2,
question: "Second question?",
answer: "blablablabla"
}
]
},
{
name: "third-category",
questions: [
{
id: 1,
question: "First question?",
answer: "First Answer"
}
]
}
];
vue file
<div class="accordion" role="tablist" v-for="eachQuestion in questionList.questions" :key="eachQuestion.id">
<FAQCollapses v-bind:eachQuestion="eachQuestion" />
</div>
//script
data () {
return {
questionList: faqData
}
}
My template code shows a blank space and there's nothing in the console so I'm confused where the mistake is. The problem is I don't know how to specifically get only one category from the faqData array, depending on what category the user clicks. Can someone tell me what is the best practice to achieve my goal? I have read all the similar questions in StackOverflow but it didn't work in my case. Thank you so much.
Best way (and a best practice, I guess), it to implement computed prop with name like, for example selectedFaqQuestion:
computed: {
selectedFaqQuestion () {
return selectedCategory ? this.faqData.find(category => category.name === this.selectedCategory).questions : []
}
}
and use it into v-for:
<div v-for="eachQuestion in selectedFaqQuestion" :key="eachQuestion.id">
<FAQCollapses v-bind:eachQuestion="eachQuestion" />
</div>
Of course, to do so, you need to implement new data prop selectedCategory, where you are going to store selected category, on user's click:
data () {
return {
questionList: faqData,
selectedCategory: null
}
}
So, as you mentioned, you need to handle user click, when going to see any questions based on selected category. To handle its click, you need to use v-on:click. To pass new value of selected category you need to update it: selectedCategory = 'somecategoryname'
'somecategoryname' means something from your faqData prop 'name', for example first-category:
<div> Please, peek FAQ category to show answers:
<span v-on:click="selectedCategory = 'first-category'"> First category </span>
<span v-on:click="selectedCategory = 'second-category'"> Second category </span>
</div>

Scroll to element when clicking table of contents

In React, how can I scroll to a heading on the page, when the corresponding heading is clicked in my table of contents?
I parse my markdown document to generate a TOC:
const toc = [
{ id: 'lorem', title: 'Lorem' },
{ id: 'ipsum', title: 'Ipsum' },
{ id: 'dolor', title: 'Dolor' }
];
I then render this TOC in render()::
{ toc.map((entry) => {
return (
<li key={entry.id}>
{entry.title}
</li>
);
})}
When I click on an entry in my TOC, I would like the page to scroll to the h2 element with that id. How?
The examples I have seen all use ref. But I am not sure how to use ref in my case, where the TOC is created dynamically at runtime and hence the refs would need to be created dynamically? I cannot add them to my document's elements, since they are generated by markdown-to-jsx.
You need to add IDs to your Markdown headers in your Markdown files and you can add IDs with this syntax:
### Lorem {#lorem}
Then in your React code you render the TOCs with link tag linking to header IDs:
{ toc.map((entry) => {
return (
<li key={entry.id}>
<a href={`#${entry.id}`}>{entry.title}</a>
</li>
);
})}
To read more about Markdown ID syntax: https://www.markdownguide.org/extended-syntax/#heading-ids

Submenu closes improperly in React + Material UI

I have a nested menu structure like follows:
menuItems = [
{
"key": "key1",
"caption": "Text1"
},
{
"key": "key2",
"caption": "Text2",
"subMenuItems": [
{
"key": "key3",
"caption": "Text3",
"subMenuItems": [
{
"key": "key4",
"caption": "Text4"
}
]
},
{
"key": "key5",
"caption": "Text5",
"subMenuItems": []
},
{
"key": "key6",
"caption": "Text6"
}
]
},
{
"key": "key7",
"caption": "Text7"
}
]
And I want to open submenu items in a submenu that opens to right side of its parent. Something similar to Angular Material Menu (Nested menu example).
I tried using Material UI Menu, and it opens the menu as needed (See here), but has the following 2 issues:
If you open the parent menu and then any of the child menu, you will need to click outside as many times as the menus. Instead, it should close all the parent + child menus on clicking outside.
If you want to switch the child menu by clicking another parent menu item, you will need to first click on the parent menu (or as per issue-1, click outside) to close the currently open child menu and then click the desired parent menu item to open corresponding child menu.
Issue 1 can be addressed using ClickAwayListener as implemented here, but then it closes all menus even when trying to switch to another child menu, like switching from "Button 3" submenu to "More Items".
Thanks.
Let's build a drawer/navbar which receives a list of items objects and render then in a recursive way. First thing first, define the structure like you already did in menuItems, i'll change it a little bit:
const items = [
{name: 'Shallow Item', path='/', type:'shallow'},
{
name: 'Nested',
type: 'nested',
items:[
{name: 'Shallow again', path='/nestedpath'}
]
}
]
Now we have two items in your list, one is a plain shallow item, which does not contain nested options, the second is a nested item which contains a list of shallow items inside it.
Now we have to build or two core components: <NestedItem> and <ShallowItem>. They should look something like this:
const ShallowItem = ({item, onClick}) =>(
<ListItem
component={Link}
to={item.path || #}
onClick={onClick ? onClick : ()=>{} }
>
<ListItemText primary={item.name}/>
{Boolean(nested) &&
<Icon>
{collapsed ? 'arrow_drop_up' : 'arrow_drop_down'}
</Icon>
}
</ListItem>
)
Notice that onClick and to(react-router link) properties had their values attributed conditionally, because we're going to use the same component to render the first layer and the list of the NestedItem, like this:
const NestedItem = ({ item }) => {
const [collapsed, toggler] = useState(false)
const classes = useStyles()
return (
<div>
<ShallowItem
item={{ icon: item.icon, title: item.title }}
nested
collapsed={collapsed}
onClick={() => toggler(!collapsed)}
/>
<Collapse in={collapsed}>
<List component='div'>
{item.items.map(item => (
<ShallowItem item={item} key={item.title}/>
))}
</List>
</Collapse>
</div>
)}
There we go, did you grabbed the ideia? The only component really getting rendered is ShallowItem cause NestedItem is just a collection of shallow items. So we first render a shallow item that opens a collapse container containing a sublist of more shallow items.The only thing that we need to do now is check if the item have subitems, case positive render a NestedItem otherwise render ShallowItem. That function is:
const renderItems = items =>{
for(let item of items){
switch(item.type){
case 'nested': return <NestedItem item={item} />
case 'shallow' : return <ShallowItem item={item} />
}
}
}
Now you have a recursive way to render nested items, you only need to stylize one component, and make the depth deeper is pretty easy now. We use this solution in our company and it works like charm.

Resources