ReactMarkdown is not displaying in React app - javascript

I'm trying to make a component that displays some simple markdown, but just can't seem to get the markdown to display on the page. It's not even creating a component for it in the HTML. This component is displaying properly and the 'Test' is showing up but not the markdown. I tried reinstalling my node_modules and that didn't work, any tips?
import React, {useState, useEffect} from 'react'
import axios from 'axios';
import {API_DEV_URL, API_PROD_URL} from '../env';
import Markdown from 'react-markdown';
const ROOT = (process.env.REACT_APP_ENV === 'production')? API_PROD_URL : API_DEV_URL;
function Hello() {
const [test, setTest] = useState("");
console.log(process.env.REACT_APP_ENV);
useEffect(() => {
axios.get(ROOT+'/test')
.then(res => setTest(res.data))
.catch(err => console.log(err));
}, []);
const input = '# This is a header\n\nAnd this is a paragraph'
return (
<header>
<h1>Test</h1>
<Markdown source={input}/>
</header>
);
}
export default Hello;

The markdown that needs to be parsed should be provided as a children. react-markdown does have make use of source prop in there API.
Change from
<Markdown source={input}/>
to
<Markdown>{input}</Markdown>

Related

How to pass state/data from one component to another in React.js (riot api specifically)

I am trying to pull information from one component's API call to then use that data in another API call in a separate component. However, I am unsure how to export and use the data from the first API call in the second component.
App.js
import './App.css';
import FetchMatch from './fetch-match/fetch.match';
import FetchPlayer from './fetch-player/fetch.player';
function App() {
return (
<div className="App">
<h1>Hello world</h1>
<FetchPlayer></FetchPlayer>
<FetchMatch></FetchMatch>
</div>
);
}
export default App;
fetch.player then makes the first API call to get a users specific ID which will be used in the second API call too fetch that users match history.
fetch.player.js
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const FetchPlayer = () => {
const [playerData, setPlayerData] = useState([]);
const userName = 'users name';
const userTagLine = '1234';
const apiKey = '???';
useEffect( () => {
axios.get(`https://americas.api.riotgames.com/riot/account/v1/accounts/by-riot-id/${userName}/${userTagLine}?api_key=${apiKey}`)
.then(response => {
console.log(response.data)
setPlayerData([response.data])
})
.catch(error => console.log(error))
}, []);
return (
<div>
{playerData.map( data => (
<div>
<p>{data.puuid}</p>
<p>{data.gameName}#{data.tagLine}</p>
</div>
))}
</div>
)
}
export default FetchPlayer;
not much here but just in case...
fetch.match.js
import React, { useState } from 'react';
// Somehow take in the puuid set in the state of fetch.player to make a second API call below
const FetchMatch = () => {
const [matchData, setMatchData] = useState([]);
return (
<div>
// players match list goes here
</div>
)
}
export default FetchMatch;
I am unsure if I should make a separate function instead which would allow me to create consts to handle both API calls in a single file. Or if there is a way to pass the state from fetch.player as a prop to fetch.match from App.js. I have tried to do the former but it either doesn't work or I am messing up the syntax (most likely this)
If you render both component parallelly in a parent component, they are called sibling components.
Data sharing in sibling components can be done by multiple ways (Redux, Context etc) but the easiest and simplest way (the most basic way without 3rd party API) involves the use of parent as a middle component.
First you create the state in the parent component and provide it as props to the child component which need the data from its sibling (in your case is FetchMatch).
import React from 'react';
import './App.css';
import FetchMatch from './fetch-match/fetch.match';
import FetchPlayer from './fetch-player/fetch.player';
function App() {
const [data,setData] = React.useState();
return (
<div className="App">
<h1>Hello world</h1>
<FetchPlayer></FetchPlayer>
<FetchMatch data={data} ></FetchMatch>
</div>
);
}
export default App;
Provide the function to setData as a props to the child component which will fetch the initial API (in your case is FetchPlayer)
<FetchPlayer onPlayerLoad={(data) => setData(data)} />
Then, in that child component when you finish calling the API and get the result, pass that result to the onPlayerLoad function which will call the setData function with the result as parameters. It will lead to state change and re-rendering of the second FetchMatch component feeding the props data with API results.
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const FetchPlayer = ({onPlayerLoad}) => {
const [playerData, setPlayerData] = useState([]);
const userName = 'users name';
const userTagLine = '1234';
const apiKey = '???';
useEffect( () => {
axios.get(`https://americas.api.riotgames.com/riot/account/v1/accounts/by-riot-id/${userName}/${userTagLine}?api_key=${apiKey}`)
.then(response => {
console.log(response.data)
setPlayerData([response.data])
onPlayerLoad(response.data)
})
.catch(error => console.log(error))
}, []);
return <></>;
Coming to FetchMatch, you will have the data in its second rendering.
import React, { useState } from 'react';
// Somehow take in the puuid set in the state of fetch.player to make a second API call below
const FetchMatch = ({data}) => {
const [matchData, setMatchData] = useState([]);
//console.log(data);
return (
<div>
// players match list goes here
</div>
)
}
export default FetchMatch;
Now, you can do whatever you want with the shared data in second component which in your case is trigger match API. 🎉

Next.js PDFtron Webviewer - ReferenceError: window is not defined

I'm trying to create a PDF viewer on my nextjs static page but i dont know how! hope you guys can help me solving this error or showing one other way to do this. (I'm new to Next.js) I was following this working example here
index.js
import SiteLayout from "../../components/SiteLayout";
import React from 'react';
import ReactDOM from "react-dom";
import Viewer from "../resume/viewer.js";
export default function Resume({ resume }) {
return (
<div>
<Viewer />
</div>
);
}
viewer.js
import React, { useRef, useEffect } from "react";
import WebViewer from "#pdftron/webviewer";
const Viewer = (props) => {
const viewer = useRef(null);
useEffect(() => {
WebViewer({
path: "/lib",
initialDoc: "/pdf/GustavoMorilla.pdf"
}, viewer.current);
}, []);
return (
<div className="Viewer">
<div className="header">React sample</div>
<div className="webviewer" ref={viewer}></div>
</div>
);
};
export default Viewer;
WebViewer needs the window object to work.
In nextjs there is a prerender phase server side and on that side window is not defined.
To solve your problem you can use next/dynamic in viewer.js
import dynamic from 'next/dynamic';
const WebViewer = dynamic(() => import('#pdftron/webviewer'), {ssr: false});
Alternatively you can import Viewer in index.js with dynamic import
import dynamic from 'next/dynamic';
const Viewer = dynamic(() => import('../resume/viewer.js'), {ssr: false});
When you import #pdftron/webviewer some code is running even though you haven't called the WebViewer function. The useEffect callback doesn't run in SSR. You can use Dynamic Imports there to import the module:
useEffect(() => {
import('#pdftron/webviewer')
.then(WebViewer) => {
WebViewer({
path: "/lib",
initialDoc: "/pdf/GustavoMorilla.pdf"
}, viewer.current);
})
}, []);
I kept getting 'window is not defined', the only solution that worked for me was following the NextJs way for importing external libraries dynamically:
useEffect(() => {
const loadWebViewer = async () => {
const WebViewer = (await import('#pdftron/webviewer')).default;
if (viewer.current) {
WebViewer(
{
path: '/lib',
initialDoc: `/api/getPdf/${encodeURIComponent(file)}/`,
disabledElements: [
'viewControlsButton',
'viewControlsOverlay',
'toolsOverlay',
'ribbonsDropdown',
'selectToolButton',
'panToolButton',
'leftPanelButton',
'toggleNotesButton',
'toolsHeader',
],
},
viewer.current
);
}
};
loadWebViewer();
}, []);

React useEffect Hook not Triggering on First Render with [] Dependencies

I'm getting data via an Axios GET request from a local API and trying to save the data in a Context Object.
The GET request works properly when I run it outside the Context Provider function. But when I put it within a UseEffect function with no dependencies - ie. useEffect( () => /* do something*/, [] )the useEffect hook never fires.
Code here:
import React, { createContext, useReducer, useEffect } from 'react';
import rootReducer from "./reducers";
import axios from 'axios';
import { GET_ITEMS } from "./reducers/actions/types";
export const ItemsContext = createContext();
function ItemsContextProvider(props) {
const [items, dispatch] = useReducer(rootReducer, []);
console.log('this logs');
useEffect(() => {
console.log('this does not');
axios.get('http://localhost:27015/api/items')
.then(data => dispatch({type: GET_ITEMS, payload: data}))
}, [])
return (
<ItemsContext.Provider value={{items, dispatch}}>
{ props.children }
</ItemsContext.Provider>
);
}
export default ItemsContextProvider;
I never see 'this does not' in the console (double and triple checked). I'm trying to initialise the context to an empty value at first, make the GET request on first render, and then update the context value.
I'd really appreciate any help on what I'm doing wrong.
EDIT - Where Context Provider is being rendered
import React from 'react';
import AppNavbar from "./Components/AppNavbar";
import ShoppingList from "./Components/ShoppingList";
import ItemModal from "./Components/ItemModal";
//IMPORTED HERE (I've checked the import directory is correct)
import ItemsContextProvider from "./ItemsContext";
import { Container } from "reactstrap"
import "bootstrap/dist/css/bootstrap.min.css";
import './App.css';
function App() {
return (
<div className="App">
<ItemsContextProvider> //RENDERED HERE
<AppNavbar />
<Container>
<ItemModal />
<ShoppingList /> //CONSUMED HERE
</Container>
</ItemsContextProvider>
</div>
);
}
export default App;
I have it being consumed in another file that has the following snippet:
const {items, dispatch} = useContext(ItemsContext);
console.log(items, dispatch);
I see console logs showing the empty array I initialised outside the useEffect function in the Context Provider and also a reference to the dispatch function.
I had the same problem for quite a while and stumbled upon this thred which did not offer a solution. In my case the data coming from my context did not update after logging in.
I solved it by triggering a rerender after route change by passing in the url as a dependency of the effect. Note that this will always trigger your effect when moving to another page which might or might not be appropriate for your usecase.
In next.js we get access to the pathname by using useRouter. Depending on the framework you use you can adjust your solution. It would look something like this:
import React, { createContext, useReducer, useEffect } from 'react';
import rootReducer from "./reducers";
import axios from 'axios';
import { GET_ITEMS } from "./reducers/actions/types";
import { useRouter } from "next/router"; // Import the router
export const ItemsContext = createContext();
function ItemsContextProvider(props) {
const [items, dispatch] = useReducer(rootReducer, []);
const router = useRouter(); // using the router
console.log('this logs');
useEffect(() => {
console.log('this does not');
axios.get('http://localhost:27015/api/items')
.then(data => dispatch({type: GET_ITEMS, payload: data}))
}, [router.pathname]) // trigger useEffect on page change
return (
<ItemsContext.Provider value={{items, dispatch}}>
{ props.children }
</ItemsContext.Provider>
);
}
export default ItemsContextProvider;
I hope this helps anyone in the future!
<ItemsContextProvider /> is not being rendered.
Make sure is being consumed and rendered by another jsx parent element.

how passing props between component using react hooks

I've retrieved datas from my database to the Recipes component. now, I'm trying to pass those datas into the RecipeList component. However, I got just the bullet points into the RecipeList component and for some reason the Recipes component return only the element " title = {recipe.title} "
I'm just starting out programming. I would be pleased if someone can help me.
Recipes
import React, {useState, useEffect} from 'react'
import axios from 'axios'
import RecipeList from '../pages/espaceUser/RecipeList'
export default function Recipes(props) {
const [recipes, setRecipes] = useState([])
const [test] = useState("text")
useEffect(() => {
const id = props.match.params.id
const getRecipes = async () => {
const url = `http://localhost:8000/user/recipes/${id}`
const result = await axios.get(url)
setRecipes(result.data)
console.log('test', result.data);
}
getRecipes()
},[])
return (
<div>
{recipes.map(recipe => (
<RecipeList
key={recipe.id}
title={recipe.title}
materiel={recipe.materiel}
ingredient={recipe.ingredient}/>
))}
</div>
)
}
RecipeList
import React from 'react'
export default function RecipeList(props) {
return (
<div>
<ul>
<li>{props.title}</li>
<li>{props.materiel}</li>
<li>{props.ingredient}</li>
</ul>
</div>
)
}
It seems to me that it is not a problem with the syntax or structure of your code, if it's rendering the title at least it means that everything is working fine. I would suggest looking at react dev tools in chrome and check out if the components have all the props they are supposed to have

shallow rendering could not find component

hi everyone I am testing my react application using jest. While testing a component I found that a test breaks unexpectedly throwing error as
Method “props” is only meant to be run on a single node. 0 found instead.
test file
import React from 'react';
import {shallow} from 'enzyme';
import {AddLibraryItem} from '../../components/AddLibraryItem';
import libraryItems from '../fixtures/libraryItems';
let addLibraryItem, history, wrapper;
beforeEach(() => {
addLibraryItem = jest.fn();
history = {push: jest.fn()};
wrapper = shallow(<AddLibraryItem addLibraryItem={addLibraryItem} history={history}/>);
})
test('should execute on submit button successfully', () => {
console.log(wrapper);
wrapper.find('LibraryItemForm').prop('onSubmit')(libraryItems[0]);
expect(addLibraryItem).toHaveBeenLastCalledWith(libraryItems[0]);
expect(history.push).toHaveBeenLastCalledWith("/");
});
Component
import React from 'react';
import {connect} from 'react-redux';
import LibraryItemForm from './LibraryItemForm';
import {addLibraryItem} from '../actions/libraryA';
export class AddLibraryItem extends React.Component {
onSubmit = (libraryItem) => {
this.props.addLibraryItem(libraryItem);
this.props.history.push('/');
}
render () {
return (
<div>
<LibraryItemForm onSubmit={this.onSubmit} />
</div>
);
}
}
const mapDispatchToProps = (dispatch) => {
return {
addLibraryItem: (libraryItem) => dispatch(addLibraryItem(libraryItem))
}
}
const ConnectedAddLibraryItem = connect(undefined, mapDispatchToProps)(AddLibraryItem);
export default ConnectedAddLibraryItem;
The piece of test was earlier working very fine and test of 'LibraryItemForm' is also working fine and also rendering perfectly.
I am not getting what is wrong with it.
Is there any fix of it?
You probably forgot to dive():
wrapper.find(LibraryItemForm).dive().prop('onSubmit')(libraryItems[0]);
Enzyme documentation here.

Categories

Resources