change source in list guesser - React-admin - symfony

I'm using React Admin, and I have this result :
As you can see, React admin displays /media_objects/:id.
I would like to display the title instead of the id.
Here is my code :
export const MediaAreasList = props => (
<ListGuesser {...props}>
<FieldGuesser label={labelLabel} source="label" />
<FieldGuesser source="title" label={titleLabel} />
<FieldGuesser source="description" />
<FieldGuesser source="mediaObjects" label={mediaObjectsLabel} />
</ListGuesser>
);
Is there a way to display titles instead of id ?
I didn't find anything in the doc
Thank you !

Do not use ListGuesser in production https://marmelab.com/react-admin/Tutorial.html
you’ll have to replace the ListGuesser component in the users
resource by a custom React component. Fortunately, ListGuesser dumps
the code of the list it has guessed to the console
In your case FieldGuesser for mediaObjects should be replaced with ReferenceManyField component:
<ReferenceManyField label={mediaObjectsLabel} reference="mediaObjects" target="...">
<SingleFieldList>
<ChipField source="title" />
</SingleFieldList>
</ReferenceManyField>
docs: https://marmelab.com/react-admin/ReferenceManyField.html

Related

nextjs links without strings

Im new to nextjs, and Im checking if it will be good for the app that will have pretty complex and messy internal navigation. Just checked their documentation and I see that they recommend usage
of Link component like this <Link href="/your_path">Path</Link>. A bit scary is that I have to provide 'your_path' as a string so every time i change page file name I have to manually update code that redirects to this page. Is there any solution that allows me to define routing on my own so I can write something like (pseudocode)
routes = [
...
{
page : 'page_name',
path : 'path_to_page'
}
...
]
So instead of using string I can do <Link href="{route.path}">Path</Link> or Im condemned to use this file-system based router with all consequences?
The simple answer is yes!
When you want to change a user route in NextJs you have 2 options,
The first is with the <Link> Element that you can specify a href to where it directs.
And you also have a useRouter hook for more complex routing for example if the user does an action that requires moving him into a different route you can do it internally in your handlers.
For more information about useRouter hook.
What I usually do is storing my routes in an object
const ROUTES = {
HOME: "/",
ABOUT: "/about"
}
and wherever you call routes you just use the object so F.E
With Link tag
<Link href={ROUTES.ABOUT}>ABOUT PAGE</Link>`
with useRouter hook
// Inside a React Component
const router = useRouter();
const handleNavigateToAbout = () => {
router.push(ROUTES.ABOUT);
}
return (
// SOME JSX
<button onClick={handleNavigateToAbout}> Go to about page! </button>
)

Algolia - AutoComplete with Suggestion + Search Results Page - NextJS

Am implementing the Algolia search in my NextJS app. I have the datasource and indices already setup. What am trying to setup is something like what Gucci is doing in their search. Gucci is using Algolia for their search functionality.
I tried using the react-instantsearch-dom package of Algolia. And I updated my /pages/_app.js file like this(only relevant code is written here):
/**
* /pages/_app.js
*
*/
//-------- Algolia
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch } from 'react-instantsearch-dom';
const searchClient = algoliasearch( 'xxxxxxxxxx', 'yyyyyyyyyyyyyyy' );
//-------- /Algolia
function MyApp({ Component, pageProps }) {
return (
<>
<InstantSearch searchClient={searchClient} indexName={ 'abc_test_products' }>
<Component {...pageProps} />
</InstantSearch>
</>
)
}
export default MyApp
This way I could use the components of react-instantsearch-dom anywhere.
Am confused at three things here.
Doubt 1:
How can I pass the algolia query and filters to the search results page like here and display the results using the components : https://www.gucci.com/us/en/st/newsearchpage?facetFilters=categoryLevel1_en%3AChildren&searchString=handbags&search-cat=header-search
So basically when the user clicks one of the algolia search suggestions(from the dropdown after clicking the search box at the top right corner of the page), they are taken to a search results page and there it seems like Algolia search is instantiated and displays the results.
Doubt 2:
How can I display the auto suggestions and product images side by side?
Doubt 3:
Displaying dynamic filter/refinement options. I understood that if there's a brand attribute in our Algoia indices/dataset, I can include that in the search filter like this:
<RefinementList attribute="brand" />
But if there are different attribute that I want to display the refinement list, say "Color", "Brand", etc. how would I display the title of the refinement option and the list dynamically from the search results.
Your UI example looks like a mash-up of a Query Suggestions panel on the left and a Hits list on the right. You can customize what a hit looks like before you render to get the image in there. And the filter menus automatically update as the user filters.
I haven't tried to get the query params into the URL, that would be interesting. I think you'd have to add useRouter into your Next page and then push the Algolia params onto the string using onClick.
Below is an example I built, maybe it helps you:
const Search = () => {
const Hit = ({ hit }) => {
return (
<HitContainer>
<span>{hit.type}</span>
<h2><a href={hit.path}>{hit.title}</a></h2>
{
hit.content &&
<p>{ `${hit.content.substring(0,150)} ...` }</p>
}
<hr />
</HitContainer>
)
}
return (
<>
<InstantSearch
searchClient={ AlgoliaReactClient }
indexName="MAINSITE" >
<CustomSearchBox
translations={{
submitTitle: 'Submit your search query.',
resetTitle: 'Clear your search query.',
placeholder: 'What are you looking for?',
}}
/>
<HitsAndFilters>
<AllFilters>
<h3>Topics</h3>
<FilterMenu
attribute="topics"
limit={5}
showMore
/>
<h3>Locations</h3>
<FilterMenu
attribute="locations"
limit={5}
showMore
/>
</AllFilters>
<AllHits hitComponent={Hit} />
</HitsAndFilters>
</InstantSearch>
</>
)
}

Nextjs Link concatenate issue

I am having an issue with the Next/Link component. My issue occurs when the user has reached the product details page. In the home page I have 3 link components that takes the user to either domain.com/headphones || domain.com/earphones || domain.com/speakers. Now in these pages the user can view a desired product which leads them to a dynamic product details page. In the product details page, I have the exact 3 link components from the home page that initially takes the user to either /headphones || /earphones || /speakers. This is where the error comes to play. The url concatenates and leads me to a 404 page.
If the user is in domain.com/speakers/productId and clicks on for example the headphones link component, the url now becomes domain.com/speakers/headphones.. when it should really just take the user back to domain.com/headphones..
Ive tried to use the replace prop in the link component as well as router.push
Any tips are greatly appreciated
const LinkCard = (props) => {
return (
<Link href={props.id}>
<li id={props.id} className={styles.linkContainer}>
<Image
src={props.src}
width={200}
height={200}
objectFit="cover"
className={styles.img}
/>
<h2>{props.title}</h2>
<div>
<p>Shop</p>
<ArrowSVG />
</div>
</li>
</Link>
);
};
export default LinkCard;
The problem is that when you redirect to with using headphones, the Next.js just concatenate the links.
Instead of that, you need to pass your target url to href like /headphones. With that way, you can redirect user to domain.com/headphones

How to make components consist between pages?

When you go to about page from index page, RestOfTheApp rerenders. Maybe it should be this way with SSR, but nextjs added static rendering like gatsby. Isn't there a way to prevent components rerendering? Like: a header shouldn't change between pages.
about.js
function index() {
return (
<>
<RestOfTheApp>
about
</RestOfTheApp>
</>
)
}
index.js
function index() {
return (
<>
<RestOfTheApp>
index
</RestOfTheApp>
</>
)
}
You can keep component state with redux I assume, but whole page re-rendering when you just need to fetch some blog content seems bloaty. I've tested with some basic layout, it still seems lightning fast but not re-rendering whole page is the main concept of SPA's, I am a little heart broken 💔
Every component that you include in a page (under /pages) will re-render no matter what you do. But it's definitely possible to add a persistent layout which doesn't re-render in NextJs. The solution is the custom app component. You can read more about it here
Following example can be helpful to understand how you can create a persistent layout:
// /pages/_app.js
import React from 'react';
import App from 'next/app';
import Layout from '../components/Layout';
class MyApp extends App {
render() {
const { Component, pageProps } = this.props
return (
<Layout>
<Component {...pageProps}></Component>
</Layout>
)
}
}
export default MyApp
In this case, the Layout component will not re-render when you navigate between pages.
#Ankit has already given a great answer on HOW to create a persistent component. Here is WHY it works.
So what really happens when you navigate from some page A (defined in pages/a.js) to another page B (defined in pages/b.js)? First, the navigation takes place on the client-side. This means instead of fetching the rendered HTML from the server, some JavaScript is run in the browser to render the new page. (You can verify it here.) The JavaScript logic of page navigation boils down to this:
The JavaScript code of the new page component <B /> is fetched from the server, if it's not already prefetched;
Next.js will call ReactDOM.render() with 2 arguments: the first one is the new React element to render (it can be roughly thought of as the updated App component), and the second one is the DOM container element (it's always <div id="__next"></div>) that the new React element is rendered into.
In short, this process can be roughly thought of as rendering the updated App component into the <div id="__next"></div> DOM container element. React will then take care of diffing the new and old React elements and decide which part of the DOM to re-render and which part to update.
So what does the new and old React element look like? Well, the default definition of the App component looks like this:
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
// Component will be set to the current page component
return <Component {...pageProps} />
}
export default MyApp
Where the Component variable will be set to the current page component. This means the old React element will look like this:
<A {...pageProps} />
and the new React element will look like this:
<B {...pageProps} />
According to the React diffing algorithm, when comparing the new and old React element, if the two elements being compared are of different types, then the corresponding subtree will be entirely destroyed and re-rendered.
That's exactly what happens in this case. <A /> and <B /> are two different components and are considered as of different types, so the part of the DOM that corresponds to <A /> will be destroyed and re-rendered as <B />.
That's why the entire page component will be re-rendered when you navigate to a new page, even if they include common components like the header.
If you put the header in the custom App components, like this:
import Header from '../components/header'
function MyApp({ Component, pageProps }) {
return (
<div>
<Header />
<Component {...pageProps} />
</div>
)
}
export default MyApp
Then the <Header /> component will persist across page navigations, because the React diffing algorithm will consider it as the same type and will only make minimal updates to the subtree.

Dynamic routing results in 404

Following this guide, I created the following file in my project:
/pages/user/[id].js
class Post extends Component {
render() {
return (
<React.Fragment>
<Navbar />
<Content />
<Footer />
</React.Fragment>
);
}
}
export default Post;
But when I go to that URL, I get a 404.
What is the problem?
Assuming you're visiting (for example), http://localhost:3000/user/something (where something is your id), try also visiting http://localhost:3000/user/something/ (note the backslash). This is currently a known issue in Next with dynamic routing.
(This also assumes you don't have pages/user/something.js in your project as dynamic routes take a back seat to explicitly named routes.)

Resources