I am trying to find the most efficient way to add syntax highlighting to my react sanity.io blog. Here's the article component that I created using react:
import React, {useEffect, useState} from "react";
import {useParams} from "react-router-dom";
import sanityClient from "../../client";
import BlockContent from "#sanity/block-content-to-react";
import imageUrlBuilder from "#sanity/image-url";
import Prism from "prismjs";
const builder = imageUrlBuilder(sanityClient);
function urlFor(source) {
return builder.image(source);
}
const serializers = {
types: {
code: (props) => (
<pre data-language={props.node.language}>
<code>{props.node.code}</code>
</pre>
),
},
};
export default function SinglePost() {
const [postData, setPostData] = useState(null);
const {slug} = useParams();
useEffect(() => {
sanityClient
.fetch(
`*[slug.current == $slug]{
title,
slug,
mainImage{
asset->{
_id,
url
}
},
body,
"name": author->name,
"authorImage": author->image
}`,
{slug}
)
.then((data) => setPostData(data[0]))
.catch(console.error);
Prism.highlightAll();
}, [slug]);
if (!postData) return <div>Loading...</div>;
return (
<article>
<h2>{postData.title}</h2>
<div>
<img
src={urlFor(postData.authorImage).width(100).url()}
alt="Author is Kap"
/>
<h4>{postData.name}</h4>
</div>
<img src={urlFor(postData.mainImage).width(200).url()} alt="" />
<div>
<BlockContent
blocks={postData.body}
projectId={sanityClient.clientConfig.projectId}
dataset={sanityClient.clientConfig.dataset}
serializers={serializers}
/>
</div>
</article>
);
}
I am importing article data from Sanity and rendering it as a component. I tried using prism.js but I am having issues getting it to work.
What's the best and most efficient way to to enable syntax highlighting?
Well, I'd use react-syntax-highlighter package on NPM. It's pretty easy to add to your project. Basically a plug-and-play. With no awkward configurations.
Related
I am learning React by making a motor cycle spec searching web application, and I am trying to import fetched data into makePicker.jsx to essentially make a drop down menu with those data.
However I am getting an error message saying:
Invalid hook call. Hooks can only be called inside of the body of a function component.
This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
I am not sure what applies to my situation. Can you see why?
makePicker.jsx
import React, {useState, useEffect} from 'react';
import {NativeSelect, FormControl} from '#material-ui/core';
import styles from './makePicker.module.css';
import { makeList } from '../../api';
const MakePicker = ()=>{
const [fetchedMakes, setFetchedMakes] = useState([]);
useEffect(()=>{
const fetchAPI = async()=>{
setFetchedMakes(await makeList());
}
fetchAPI();
},[])
return (
<h1>makePicker</h1>
);
}
export default MakePicker;
App.js
import logo from './logo.svg';
import './App.css';
import {fetchData, makeList} from './api/index';
import React, {Component} from 'react';
import MakePicker from './components/makePicker/makePicker';
class App extends React.Component{
state = {
data:[],
makes:[],
}
async componentDidMount(){
// const fetchedData = await fetchData();
const fetchedMakeList = await makeList();
this.setState({makes:fetchedMakeList});
}
render(){
return (
<div className="App">
<header className="App-header">
{MakePicker()};
<h1>Some line-ups from YAMAHA</h1>
{this.state.makes.map(make=>{
return <p>{make.name}</p>
})}
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Open React
</a>
</header>
</div>
);
}
}
export default App;
Please let me know if need more information from my project.
According to your code in App.jsx and following the naming convention of React's component, you should import it with the first-capitalized-letter name like below
import MakePicker from './components/makePicker/makePicker';
You're also calling {makePicker()}; which is not a proper way for component rendering. You should modify it to
<MakePicker/>
Full possible change can be
import logo from './logo.svg';
import './App.css';
import {fetchData, makeList} from './api/index';
import React, {Component} from 'react';
import MakePicker from './components/makePicker/makePicker';
class App extends React.Component{
state = {
data:[],
makes:[],
}
async componentDidMount(){
// const fetchedData = await fetchData();
const fetchedMakeList = await makeList();
this.setState({makes:fetchedMakeList});
}
render(){
return (
<div className="App">
<header className="App-header">
<MakePicker/>
<h1>Some line-ups from YAMAHA</h1>
{this.state.makes.map(make=>{
return <p>{make.name}</p>
})}
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Open React
</a>
</header>
</div>
);
}
}
export default App;
To elaborate more why you get this error
Invalid hook call. Hooks can only be called inside of the body of a function component.
When you call makePicker(), it's actually triggering a Javascript's function (not React's component as you expected), but useEffect is only available in React's components. That's why when you try to run code, the compiler is thinking makePicker is calling useEffect invalidly.
Their is a problem lies on your useEffect
update the code like this and try it out:
const fetchAPI = async()=>{
const res = await makeList().then((data) => {
setFetchedMakes(data)
}).catch((err) => console.log(err))
}
useEffect(()=>{
fetchAPI();
},[])
here i placed the asynchronous function outside of the useEffect
Also make MakePicker as an JSX element like this: <MakePicker />
Ok, so. I am currently following this tutorial: https://www.freecodecamp.org/news/react-movie-app-tutorial/ . I have copied the code verbatim. I have installed bootstrap via the instructions on this website: https://react-bootstrap.github.io/getting-started/introduction#stylesheets . I have tried every configuration in every place of importing 'bootstrap/dist/css/bootstrap.min.css' including the <link>. The Row class is not working. Here is my Code...
import 'bootstrap/dist/css/bootstrap.min.css'
import './index.css'
import MovieList from "./components/MovieList"
const App = () => {
const [movies, setMovies] = useState([])
//const [favorite, setFavorite] = useState([])
//const [searchValue, setSearchValue] = useState("")
const getMovieRequest = (searchValue) => {
const url = `http://www.omdbapi.com/?s=jaws&apikey=76fd1ead`
fetch(url)
.then(resp => resp.json())
.then(data => {
if (data.Search) {
setMovies(data.Search)
}
})
}
useEffect(() => {
getMovieRequest()
}, [])
console.log(movies)
return (
<div className="container-fluid">
<div className="row">
<MovieList movies={movies} />
</div>
</div>
)
}
export default App;
import React from "react"
/*export default function MovieList(props) {
const displayMovies = props.movies.map(movie => {
return (
<div>
<img src={movie.Poster} alt="moive" />
</div>
)
})
return(
<>
{displayMovies}
</>
)
}*/
const MovieList = (props) => {
return (
<>
{props.movies.map((movie, index) => (
<div>
<img src={movie.Poster} alt="movie" ></img>
</div>
))}
</>
)
}
export default MovieList;
import React, {useState} from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Any help would be greatly appreciated!
There is "bootstrap" itself and it is independent of what kind of framework you are using (React, Vue, Angular or just vanilla). It uses mostly css classes and jQuery for some functionality. Then there is "react-bootstrap", which is a complete re-write of bootstrap logic. It's written in React and offers a collection of components. That's why when you use react-bootstrap you only need the css part of bootstrap, but not the js/jQuery part.
Using only bootstrap?
npm i bootstrap
import 'bootstrap/dist/css/bootstrap.min.css' in your App.js or index.js
https://codesandbox.io/s/crazy-meninsky-9lmpmr?file=/src/App.js
Using react-bootstrap?
npm i react-bootstrap boostrap
import 'bootstrap/dist/css/bootstrap.min.css' in your App.js or index.js
https://codesandbox.io/s/serene-heisenberg-1xfvut
When you look into the both sandboxes you see that row is working either way.
I'm trying to run the blog example in material ui getting started page . the problem is that the source code is:
in blog.js
import post1 from './blog-post.1.md';
.
.
.
return( <Main>{post1}<Main/>);
and in Main.js:
import ReactMarkdown from 'markdown-to-jsx';
export default function Main(props) {
return <ReactMarkdown options={options} {...props} />;
}
if I run the code I get this output:
/static/media/blog-post.1.0c315da1f0a7af641a3a.md instead of the data inside the MD file.
I want to do the same ,how can I import MD files in my create-react-app version? (without typescript)
You'll need to read the markdown object and then load it into the ReactMarkdown component. Common methods of doing this use fetch as an intermediary. For example:
import * as React from "react";
import ReactMarkdown from "markdown-to-jsx";
import post from "./post.md";
export default function MarkdownImport() {
let [readable, setReadable] = React.useState({ md: "" });
React.useEffect(() => {
fetch(post)
.then((res) => res.text())
.then((md) => {
setReadable({ md });
});
}, []);
return (
<div>
<ReactMarkdown children={readable.md} />
</div>
);
}
Working example: https://codesandbox.io/s/reactmarkdown-example-20vmg
I have implemented mgt-login component from Microsoft Graph toolkit, it is working fine but it's not calling event I added to mgt-login within useEffect. Duplicate question here - I did follow this question but still its not calling event I added. Here is code for that component
import React, {
useRef,
useEffect,
} from 'react';
const Login = () => {
const loginComponent = useRef(null);
useEffect(() => {
loginComponent.current.addEventListener('loginCompleted', () => console.log('Logged in!'));
}, []);
return (
<div className="login">
<mgt-login ref={loginComponent} />
</div>
);
};
Here is how instantiate Provider in main index.jsx file of app
import { Providers, MsalProvider } from '#microsoft/mgt';
Providers.globalProvider = new MsalProvider({
clientId: process.env.REACT_APP_DEV_AZURE_APP_CLIENT_ID,
});
I don't know what I am missing, not sure if something was updated about this component(BTW, I have not found any change in microsoft graph docs).
Thanks!
To make the use of mgt components in React easier, we created a React wrapper that you can use here, mgt-react.
import React, {
useRef,
useEffect,
} from 'react';
import {Login} from '#microsoft/mgt-react';
const Login = () => {
return (
<div className="login">
<Login loginCompleted={(e) => console.log('Logged in')} />
</div>
);
};
I have been trying to build a little site using GatsbyJS with protected content using Firebase, following this example:https://github.com/taming-the-state-in-react/gatsby-firebase-authentication. I am using DatoCMS as a source. I have built blogs before where everything was the same except for the firebase authentication part, and everything worked perfectly fine.
Somehow, I get the error of data not being defined inside my template file out of which the article-pages are generated.
Here is my code:
import React from 'react'
import AuthUserContext from '../components/Session/AuthUserContext';
import withAuthorization from '../components/Session/withAuthorization';
import { graphql } from 'gatsby';
const authCondition = authUser => !!authUser;
const WikiPageSingle = withAuthorization(authCondition)(() => (
<AuthUserContext.Consumer>
{authUser => (
<div>
<h1>{this.props.data.datoCmsArticle.id}</h1>
</div>
)}
</AuthUserContext.Consumer>
))
export default withAuthorization(authCondition)(WikiPageSingle);
export const query = graphql`
query ArticlQuery ($slug: String!) {
datoCmsArticle (slug: { eq: $slug }) {
id
title
slug
}
}
`;
I know it might be hard to get help on this since its kind of a very specific issue but any ideas or pointers why this wouldn't work on a template file would be much appreciated!
I managed to get it working by creating a new layout for those articles and basically protecting the whole content inside that layout. I still feel there must be a more elegant solution so any ideas are more than welcome. In the meantime, here is how I got it working in case someone else has this issue in the future:
New Layout component:
import React from 'react';
import AuthUserContext from '../components/Session/AuthUserContext';
import withAuthorization from '../components/Session/withAuthorization';
import withAuthentication from './Session/withAuthentication';
const authCondition = authUser => !!authUser;
const ArticleLayout = withAuthorization(authCondition)(({children}) => (
<AuthUserContext.Consumer>
{authUser => (
<div>
{children}
</div>
)}
</AuthUserContext.Consumer>
));
export default withAuthentication(ArticleLayout);
And here my template in the templates folder:
import React from 'react';
import { graphql } from 'gatsby';
import ArticleLayout from '../components/articlelayout';
class BlogPost extends React.Component {
render() {
return (
<ArticleLayout>
<div>
<h1>{this.props.data.datoCmsArticle.title}</h1>
</div>
</ArticleLayout>
)
}
}
export default BlogPost
export const query = graphql`
query PostQuery ($slug: String!) {
datoCmsArticle (slug: { eq: $slug }) {
id
title
slug
}
}
`;