Data Not Rendering Using Next Js - next.js

I'm trying to use data from an API following the steps provided in the Next docs. My data does not render, this is my first foray into React so I'm not sure what I'm missing. Would somebody mind pointing out my error please?
export default function Home({ items }) {
console.log(items) // Items listed in the console fine
return (
<ul>
{items.map((item, index) => {
<li key={index}>{item.description}</li>
})}
</ul>
)
}
export async function getStaticProps() {
// Get Data Here
return { props: {
items
}}
};
As you can see by my note above, the console lists the items as expected. I can also see the items array in the React Dev Tools in chrome.
The below console.logs as expected but again nothing is rendered to the browser.
export default function Home({items}) {
return (
<ul>
{items.map((item, index) => {
console.log(item.description);
<li key={index}>{item.description}</li>
})}
</ul>
)
}

{items.map((item, index) => {
console.log(item.description);
<li key={index}>{item.description}</li>
})}
should be:
{items.map((item, index) => {
console.log(item.description);
return <li key={index}>{item.description}</li>
})}

Related

Next.js 13 routing params

Hi folks first of all i am new to react and nextjs. So i am sorry if my question is stupid.
I am currently building a navigation with nextjs 13 within new the app folder. Here is my navigation component where i am building the category links with the component:
import React from 'react'
import fetchMainNavigation from '../lib/fetchMainNavigation'
import Link from 'next/link'
const DesktopNavigation = async () => {
const categories = await fetchMainNavigation
return (
<nav className={'hidden md:flex'}>
<ul className={'flex flex-row gap-4'}>
{categories.map((category) => (
<li key={category.id}>
<Link
href={`${category.id}`}
className={
'hover:underline hover:text-gold hover:scale-110 transition-transform duration-200'
}
>
{category.name}
</Link>
</li>
))}
</ul>
</nav>
)
}
export default DesktopNavigation
export async function generateStaticParams() {
const categories = await fetchMainNavigation
return categories.map((category) => ({
categoryId: category.id.toString(),
}))
}
I have also created a dynamic route "/app/[categoryId]/page.jsx". The routing works fine but now i have a not readable URL like "www.mypage.com/46asdfg56as8g" but i want something like "www.mypage.com/food". I know i could use the category name for routing but i need the categoryId as param within "/app/[categoryId]/page.jsx" to fetch information about the current active category. Is there a way to achieve this?
I have already searched the Next.js 13 documentation and also searched stackoverflow and other sources, but can't find anything about this problem yet.
It is in the beta documentation here. Also, under the very first category of the docs here
To utilize the next13 beta slugs, simply pass them in as the params property, as outlined in the official documentation.
const DesktopNavigation = async ({ params }) => {
const category = params['category'];
...
}

Next.js: Passing data to nested routes

Issue:
Right now, I have a dynamic route that fetches data using getServerSideProps(). Within this page, there are multiple tabs that renders different data depending on state (which tab is selected).
I wish to transition from using multiple tabs on this page, to instead using nested routes. However, I am having difficulty obtaining the data originally fetched in these nested routes. Is there an efficient way of doing so, without having to call getServerSideProps() again?
My intended setup looks like this, where [page] calls getServerSideProps():
[page].jsx
|_tab1.jsx
|_tab2.jsx
|_tab3.jsx
My current [page].jsx, where I would like to use separate, nested pages that have access to these props (instead of rendering each tab based on state):
export default function Page(props) {
const [currentTab, setCurrentTab] = useState("home");
return (
<div>
<div id="tab1" onClick={() => setCurrentTab("home")}>
home
</div>
<div id="tab2" onClick={() => setCurrentTab("posts")}>
posts
</div>
<div id="tab3" onClick={() => setCurrentTab("info")}>
info
</div>
{currentTab === "home" ? (
<HomeTab props={props}/>
) : currentTab === "posts" ? (
<PostsTab props={props}/>
) : (
<InfoTab props={props}/>
)}
</div>
);
}
Attempts
I've attempted using the context API to utilize data globally, which my other pages can use. However, this requires the user to visit the original dynamic route first.
Call getServerSideProps() on each nested route. Although this works, I wish to find a better solution, since I'm fetching data on each nested route while the route they're nested under has all of this data available already.
You can use shallow routing in next/route or next/link
Note that, in the below example, I'm using next/link for the demonstration. Without your tab data, I'd assume you have an array of tabs in data
import { useEffect } from 'react'
import Link from 'next/link'
//the path is `/tab/:tabId`
function Tab({ data }) {
const [tabData, setTabData] = useState(data[0]) //first tab data as default for example
useEffect(() => {
setTabData(data[tabId])
}, [router.query.tabId])
return <>
<Link href="/tab/0" shallow />
<Link href="/tab/1" shallow />
<div>
{tabData}
</div>
</>
}
export async function getServerSideProps(context) {
return {
props: {
data: [], //tabs' data you fetched from the API
},
}
}
export default Tab

How to solve this forEach loop problem in wp?

In one of my WordPress Project, I had to post a get request and render the response data in the front end. To render the data I tried to use the forEach() loop but it always shows undefined but the same thing works fine if I use map().
Now I just want to know what's the problem with forEach(). I am giving both the working and not working code below:
Not working:
getResults() {
$.getJSON(`http://localhost/from_wp_course/wp-json/wp/v2/posts?search=${this.searchField.val()}`, posts => {
this.resultsDiv.html(`
<h2 class="search-overlay__section-title">General Information</h2>
<ul class="link-list min-list">
${posts.forEach(item => `<li>${item.title.rendered}</li>`)}
</ul>
`);
});
}
Working:
getResults() {
$.getJSON(`http://localhost/from_wp_course/wp-json/wp/v2/posts?search=${this.searchField.val()}`, posts => {
this.resultsDiv.html(`
<h2 class="search-overlay__section-title">General Information</h2>
<ul class="link-list min-list">
${posts.map(item => `<li>${item.title.rendered}</li>`).join('')}
</ul>
`);
});
}
.foeEach return value is undefined (why you get the undefined) but .map returns a new array.

How can I disable the toolbars for core blocks? Is this possible at all?

I'm trying to disable the toolbars for all core blocks to keep the editors from unnecessarily formatting the content. Is that even possible?
My current approach is:
wp.blocks.getBlockTypes().forEach((blockType) => {
// unregister all default styles (from the right sidebar)
let blockName = blockType.name;
if ( blockType.hasOwnProperty('styles')) {
blockType.styles.forEach( (style) => {
wp.blocks.unregisterBlockStyle( blockName, style.name );
});
}
});
Can I somehow access the toolbars in this loop? Do I understand it correctly that I have to override the edit and save methods of the core blocks, probably with a filter?
Thanks, Patrik
I have just solved the problem, but different than intended.
Basically, the solution for me was to deregister the required core blocks, make changes to the edit and save methods, and then re-register the blocks.
A great help was this blog article by Riad Benguella:
https://riad.blog/2017/10/16/one-thousand-and-one-way-to-extend-gutenberg-today/
Here's an example based on a core / quote block:
const TextControl = wp.components.TextControl;
import './style.scss';
import './editor.scss';
wp.domReady( () => {
let unregisteredBlock = wp.blocks.unregisterBlockType('core/quote');
unregisteredBlock.title = 'Quotation';
unregisteredBlock.icon = 'format-quote';
unregisteredBlock.edit = ({ attributes, setAttributes} ) => {
const updateFirstValue = ( val ) => {
setAttributes({
value: val
});
};
const updateSecondValue = ( val ) => {
setAttributes({
citation: val
});
};
return (
<div>
<TextControl
label='Quote'
value={ attributes.value }
onChange={ updateFirstValue }
/>
<TextControl
label='Citation'
value={ attributes.citation }
onChange={ updateSecondValue }
/>
</div>
);
};
unregisteredBlock.save = ( { attributes, className } ) => {
return (
<blockquote className={className}>
<p>{attributes.value}</p>
<cite>{attributes.citation}</cite>
</blockquote>
)
};
wp.blocks.registerBlockType('core/quote', unregisteredBlock);
});
In principle, both the edit and save method are replaced here, only the block attributes are reused from the core blocks. Due to the fact that new elements are used to enter the content, the toolbars are not the problem anymore.
I hope this can help someone who has the same problem.
Cheers,
Patrik

trying to render a list. nothing showing on screen

Using Meteor and React. Trying to render a list of data from the server onto the client. the server's data looks like this:
Searches.insert({text: data.items[i].snippet.title});
if(Meteor.isClient) {
Searches = new Meteor.Collection('searches');
Meteor.subscribe('allSearches');
}
....
renderTasks(){
return this.data.searches.map((searches) => {
return <SearchResultItem searches={searches} />;
});
},
....
<ul>
{this.renderTasks()}
</ul>
....
SearchResultItem = React.createClass({
render(){
return
<li>
{this.props.searches.text}
</li>
}
});
You need to provide an unique key-prop to your dynamic child elements
Dynamic Children
The situation gets more complicated when the children are shuffled around (as in search results) or if new components are added onto the front of the list (as in streams). In these cases where the identity and state of each child must be maintained across render passes, you can uniquely identify each child by assigning it a key:
render: function() {
var results = this.props.results;
return (
<ol>
{results.map(function(result) {
return <li key={result.id}>{result.text}</li>;
})}
</ol>
);
}
(REF: https://facebook.github.io/react/docs/multiple-components.html#dynamic-children)
In your case:
renderTasks(){
return this.data.searches.map((searches, i) => {
return <SearchResultItem key={i} searches={searches} />;
});
}

Resources