Multi lingual react application with JSON.JS (as backend) - reactjs

I developed a web application and it is a dynamic site. Can I place a multilingual option for my site? I go further to develop a multilingual application? I have got through many provided solution with i18next but thats the solution for static data.
I have reusable components with props. When I map through the data imported from JSON, I can't handle and apply i18next (static key concept). Is there any solution please.
For more details, here is the scenario,
import React, {useEffect, useState} from 'react';
import ObjectiveCard from './ObjectiveCard';
// import objectiveData from '../../../../assets/resume_eng.json';
// import objectiveData from '../../../../assets/resume_dk.json';
import axios from 'axios';
const Objective = () => {
const [objective, setObjective] = useState(null)
useEffect(() => {
axios.get('http://localhost:9000/objective')
.then(response => setObjective(response.data))
}, [])
return (
<div>
{objective && objective.map((o, index) => {
return(
<ObjectiveCard
key={index}
myName={o.name}
jobTitle={o.jobTitle}
objective={o.objective}
/>
)
})}
</div>
)
}
export default Objective;
and child component is,
const ObjectiveCard = (props) => {
return (
<div>
<h1> {props.myName} </h1>
<h3> {props.jobTitle} </h3>
<p>
{props.objective}
</p>
</div>
);
}
export default ObjectiveCard;

Related

Fetch navigation from API in the next.js and render it at initial load of the page for better SEO

i am very new to React/NEXT.JS and i guess i am facing a issue where i want to fetch data for my dynamic navigation bar, which is available on all the pages. I am using context API to set the value and fetch 1 time at the initial render of the whole document. Then it should show navigation items directly.
Here is how i am trying to do it.
import { createContext, useState, useEffect } from "react";
import Layout from "../components/layout";
import "../styles/globals.css";
import BasicProviders from "../helpers/BasicProviders";
export const NavContext = createContext();
function MyApp({ Component, pageProps, navigationItems }) {
const [navitems, setNavitems] = useState(navigationItems);
return (
<NavContext.Provider value={{ navitems }}>
<Layout>
<Component {...pageProps} />
</Layout>
</NavContext.Provider>
);
}
MyApp.getInitialProps = async (ctx) => {
const res = await fetch("http://www.myserver.com/navigation");
console.log(res);
return { navigationItems: res };
};
export default MyApp;
Now i have folder structure like this:
- components (in root directory of next.js)
- layout.js
- /Header
- DesktopNav.js <<<<<--------------- here i want to send my value of **navitems**
- Header.js
This is how my DesktopNav.js is looking :
import Link from "next/link";
import React, { useContext } from "react";
import NavContext from "../../stores/NavContext";
import DesktopSubMenuLoop from "./DesktopSubMenuLoop";
export default function DesktopNav() {
const { navitems } = useContext(NavContext);
return (
<nav>
<DesktopSubMenuLoop navitems={navitems}></DesktopSubMenuLoop>
</nav>
);
}
Somehow it is sending the data to the component. But everytime i click on the Navigation Link it reloads the complete page. Not sure how i can achieve this. For the time being i am using useEffect to do achieve the same. But that is not SEO compatible.
Problems need to be solved here:
API should be called once for whole page. As the navigation will stay same for all the pages.
Page routing should be as smooth as it is with static tags. Currently it reloads the page like a static HTML web page.
Possible solutions i though of:
is there any way i can fetch the navitems on _document.js and send to _app.js?
Calling the API on each page with getServerSideProps but that will make all of my pages non-static for internal pages as well at the build time.
Any solution i can get on this will be really helpful and thankful.
#juliomalves for you:
MainNavigation Loop currently i am using useEffect to display the navigation, but as per my understanding its not good for SEO.
You can check my loop here DesktopSubMenuLoop.js
import Link from "next/link";
import React from "react";
export default function DesktopSubMenuLoop({ navitems, isSubmenu = false }) {
return (
<ul className={isSubmenu ? "sub-menu-style" : ""}>
{navitems.map((item, index) => (
<li key={item.id}>
<Link href={item.slug !== "/" ? `/${item.slug}` : item.slug}>
<a>
{item.title}{" "}
{item.children && item.children.length > 0 && (
<i className="icon-arrow-down"></i>
)}
</a>
</Link>
{item.children && item.children.length > 0 && (
<DesktopSubMenuLoop
key={item.id}
navitems={item.children}
isSubmenu={true}
></DesktopSubMenuLoop>
)}
</li>
))}
</ul>
);
}

Learning React: Trouble understanding why my component won't render/ API/KEYS

I am fairly new to learning React and need some help.
I want to create a meal finder app using the MealDb API, my problem is it won't render.
Here is my code, in my app component:
import React, { useState } from 'react';
import './App.css';
import Search from './components/Search';
import Meals from './components/Meals';
import axios from 'axios';
function App() {
const [meals, setMeals] = useState({});
const searchMeals = async meals => {
const res = await axios.get(
`https://www.themealdb.com/api/json/v1/1/search.php?s=${meals}`
);
console.log(res.data);
setMeals({ meals: res.data });
};
return (
<div className='App'>
<Search searchMeals={searchMeals}></Search>
<Meals searchMeals={searchMeals} meals={meals}></Meals>
</div>
);
}
export default App;
I created a component Meals with this inside:
import React from 'react'
import MealsItem from './MealsItem'
const Meals = ({ meals}) => {
return (
<div >
{Object.keys(meals).map(meal=>(
<MealsItem key={meal.idMeal} meal={meal}/>
))}
</div>
);
};
export default Meals
and then for the rendering part I created a MealsItems component:
import React, { Fragment } from 'react';
const MealsItem = ({ meal :{strMealThumb, strMeal,}}) => {
return (
<Fragment>
<div id='result-heading'>
<h2>Search result for: {strMeal}</h2>
</div>
<div className='meal'>
<img src={strMealThumb} alt={strMeal} />
<div className='meal-info'>
<h3>{strMeal}</h3>
</div>
</div>
</Fragment>
);
};
export default MealsItem;
When I search something: I see a unique item with nothing in it. No title, no image. In the console when I inspect the app I read {meals: Array(8)} and "Warning: Each child in a list should have a unique "key" prop." I thought did write a unique key: key={meal.idMeal}.
EDIT: I did try to write
{meals.map(meal=>(
))}
to no avail, unfortunately. It gives me a type error meals.map is not a function.
This is the structure of the API:
{
"meals": [
{
"idMeal": "52772",
"strMeal": "Teriyaki Chicken Casserole",
"strDrinkAlternate": null,
"strCategory": "Chicken"
}
]
}
Edit # 2: This is what I get when I console.log(meals)
console.log(meals)
Thank you to anyone willing to help! Have a good day!
Reason is that you are using
Object.keys(meals).map.
Instead, do this
{meals.map(meal=>(
<MealsItem key={meal.idMeal} meal={meal}/>
))}
EDIT: Also set default value of meals state.
const [meals, setMeals] = useState([]); // dont use useState({})
Otherwise in the initial render before meals are fetched there will be error as we try to map over an object.

React - Importing the JSON object only once

The following simple React component is importing a JSON file (data.js) as an object and list the items inside it.
List.js
import React from 'react'
import jsonResponse from './data'
function ZooList ({ setID }) {
const setURL = (e) => {
window.history.pushState(null, null, '/' + e)
setID(e)
}
const list = jsonResponse.animals.map((item) => {
return (
<li key={item.id}>
<div>
<img
src={item.image_url}
alt={item.name}
onClick={() => setID(item.id)}
/>
<h3>{item.name}</h3>
<p>
<b>Distribution</b>: {item.distribution}
</p>
<button onClick={() => setURL(item.id)}>More...</button>
</div>
</li>
)
})
return (
<ul>
{list}
</ul>
)
}
export default List
Now in the above page, if you click on button "More...", it calls another React component called Tile.js as fallow:
Tile.js
import React from 'react'
import jsonResponse from './data'
function Tile ({ setID, newID }) {
const clearURL = (e) => {
window.history.pushState(null, null, '/')
setID(null)
}
return (
<div>
<div>
<img
src={jsonResponse.animals[newID].image_url}
alt={jsonResponse.animals[newID].name}
/>
<h2>{jsonResponse.animals[newID].name}</h2>
<p><b>Distribution</b>: {jsonResponse.animals[newID].distribution}</p>
<StyledParagraph>{jsonResponse.animals[newID].details.long}</StyledParagraph>
<button onClick={() => clearURL(null)}>Back to overview</button>
</div>
</div>
)
}
export default Tile
The problem is that the second component is also importing the JSON file (data.js).
How can I avoid importing the data.js twice?
Generally, what would be a better way to write this app?
Imports are cached, so if you return directly a JSON with import jsonResponse from './data', the first component will import it, while the second will get it from import cache;
You can try for example, to export an instance of a class, change one of its property and then check that property in another component that make use of that import.
A ready-to-pick and very common usage example of that cache is the configureStore of react-boilerplate: it exports the store instance so whatever component import it will refer to the same store.

Is there a way in React Javascript to pass props and use it in external import?

I want to pass props from one component to another, and use it in the second one for an import above the component declaration
This is for using the same component, with no need to create it 4 times, every time with another SVG.
I'm using React, Javascript, Webpack, babel.
I'm also using svgr/webpack to create a component from an SVG picture, and it's crucial for me to use SVG not < img >.
import React from 'react';
import RightNavItem from './right_nav_item';
const RightNav = ({navitems}) => {
const rightNavItems = navitems.map( (item) => {
return <RightNavItem name={ item }/>
});
return(
<div className="rightnav">
{rightNavItems}
</div>
);
};
.
export default RightNav;
import React from 'react';
const RightNavItem = ({ name }) => {
const svgpath = `../../../../resources/img/navbar/${name}.svg`;
return(
<div>
<img src={ svgpath } style={{height: '25px'}}/>
<span>{ name }</span>
</div>
);
};
export default RightNavItem;
And I want to achieve being able to do this:
import React from 'react';
import SvgPicture from '../../../../resources/img/navbar/{name}.svg';
const RightNavItem = ({ name }) => {
return(
<div>
<SvgPicture />
<span>{ name }</span>
</div>
);
};
export default RightNavItem;
.
Ok so I went back and implemented the whole thing on my local app to get exactly what you need. I am editing my original answer. Hope this solves your issue.
The parent:
import React from 'react';
import { ReactComponent as svg } from 'assets/img/free_sample.svg';
import RightNavItem from './RightNavItem';
const LOGOS = [
{ name: 'home', svg },
{ name: 'home', svg },
];
const RightNav = () => (
<div>
{LOGOS.map(logo => (
<RightNavItem name={logo.name}>
<logo.svg />
</RightNavItem>
))}
</div>
);
export default RightNav;
The child:
import React from 'react';
const RightNavItem = ({ name, children }) => (
<div>
{children}
<span>{name}</span>
</div>
);
export default RightNavItem;
You don't need to import the svg as I did, if you are able to use svg as a component in your webpack config then continue to do what you were doing before.
I managed to do it in a kind of ugly way, but it works.
The problem is if I have more than 4 items, then using it without the map() function can be really annoying.
I used {props.children}, and instead of using map(), I added the 4 times, each with different 'SVG' component child and different props 'name', that way the component only gets initialized at the RightNavItem level.
IF SOMEONE KNOWS how can I use this with the map() function, It'll help a lot!
Thanks to everyone who helped!
For example:
const RightNav = (props) => {
return(
<div className = "rightnav">
<RightNavItem name = {home}>
<HomeSVG />
</RightNavItem>
<RightNavItem name = {profile}>
<ProfileSVG />
</RightNavItem>
.
.
.
</div>
);
};
And in the RightNavItem:
const RightNavItem = (props) => {
return(
<div>
{props.children}
<span>{ props.name }</span>
</div>
);
};

React-ga not returning correct active page in Google Analytics Dashboard

Context: In the app, I am using react-slick to allows users to navigate through components like a carousel. (NOTE: as users navigate through the carousel, the URL for the application does not change/update; always https: //myApplicationURL.com)
What I am attempting to accomplish: Each component within the carousel uses react-ga to initialize and track pageview analytics on a component level.
What I expect: Google Analytics dashboard will return the correct component name a user is currently viewing.
What is actually happening: Google Analytics dashboard displays an incorrect component name. (Ex: application is on contact component - should display '/contact' but GA dashboard displays another component name)
**CAROUSEL COMPONENT**
import React, { Component } from "react";
import Slider from "react-slick";
import ReactGA from 'react-ga';
import About from '../../components/about';
import {default as Project1} from '../../components/projectTemplate';
import {default as Project2} from '../../components/projectTemplate';
import {default as Project3} from '../../components/projectTemplate';
import {default as Project4} from '../../components/projectTemplate';
import Contact from '../../components/contact';
export default class Carousel extends Component {
constructor(props) {
super(props);
this.state = {
nav1: null,
nav2: null,
pageNumber: 0
};
}
componentDidMount() {
this.setState({
nav1: this.slider1,
nav2: this.slider2
});
}
afterChangeHandler = currentSlide => {
this.setState({
pageNumber: currentSlide++
})
};
render() {
const carousel1 = {
asNavFor: this.state.nav2,
ref: slider => (this.slider1 = slider),
afterChange: this.afterChangeHandler
}
const carousel2 = {
asNavFor: this.state.nav1,
ref: slider => (this.slider2 = slider),
}
return (
<div id="carousel-container">
<Slider {...carousel1}>
<div>
<About props={this.props.props} />
</div>
<div>
<Project1 project={this.props.props.project[0]} />
</div>
<div>
<Project2 project={this.props.props.project[1]} />
</div>
<div>
<Project3 project={this.props.props.project[2]} />
</div>
<div>
<Project4 project={this.props.props.project[3]} />
</div>
<div>
<Contact {/*props*/} />
</div>
</Slider>
<Slider {...carousel2}>
{/*slider2 content*/}
</Slider>
</div>
);
}
}
**ABOUT COMPONENT**
import React from 'react';
import ReactGA from 'react-ga';
const About = props => {
//Google Analytics
ReactGA.initialize('[User ID removed]');
ReactGA.ga('set', 'page', '/about');
ReactGA.ga('send', 'pageview');
return(
<div id="aboutContainer">
{/*Component Content*/}
</div>
);
};
export default About;
**PROJECT COMPONENT**
import React from 'react';
import ReactGA from 'react-ga';
const ProjectTemp = props => {
const name = props.project.name
// Google Analytics
ReactGA.initialize('[User ID removed]');
ReactGA.ga('set', 'page', `/project/${name}`);
ReactGA.ga('send', 'pageview');
return(
<div id="projectTempContainer">
{/*Project Content*/}
</div>
);
};
export default ProjectTemp;
**CONTACT COMPONENT**
import React from 'react';
import ReactGA from 'react-ga';
const Contact = props => {
//Google Analytics
ReactGA.initialize('[User ID removed]');
ReactGA.ga('set', 'page', '/contact');
ReactGA.ga('send', 'pageview');
return(
<div id="contactContainer">
{/*Contact Content*/}
</div>
);
};
export default Contact;
I suggest using the Segment analytics library and following our React quickstart guide to track page calls. If you are rendering individual components inside the carousel, you can use componentDidMount to invoke page calls. You’ll be able to manually set the page name via the parameter, which will help you avoid the issue you’re having with /contact. The example below shows one way you could do this:
export default class CarouselContact extends Component {
componentDidMount() {
window.analytics.page('Contact');
}
render() {
return (
<h1>
Contact page.
</h1>
);
}
}
I’m the maintainer of https://github.com/segmentio/analytics-react. With Segment, you’ll be able to switch different destinations on-and-off by the flip of a switch if you are interested in trying multiple analytics tools (we support over 250+ destinations) without having to write any additional code. 🙂

Resources