React variable image relative to url - reactjs

I would like to change the background image depending on the view file/URL. I don't quite know how to do this, I have 3 different images and 3 different views of Mindhunter, Sherlock etc. On "/mindhunter" there should be a mindhunter banner and on "/sherlock" a sherlock banner
Background.js
import React from 'react';
import sherlockBaner from 'assets/SherlockBaner.svg';
const Background = () => {
return (
<>
<div>
<img className="baner" src={sherlockBaner} alt="baner" />
</div>
</>
);
};
export default Background;
Mindhunter.js
import React from 'react';
import Background from 'components/Series/Background/Background';
const Mindhunter = () => {
return (
<>
<Background />
</>
);
};
export default Mindhunter;

Depending on how dynamic you want to make this you have two options:
Passing the "src" as a property to Background, and using props.src to set your img src
Using the path in your router to determine which url you have (take a look at react-router and query params) and then pass that into your component, which will then use some switch to select the correct background.
Let me know if you want more information on 1 or 2.

I came up with something like this, it could probably be improved somehow
import React from 'react';
import mindHunterBaner from 'assets/MindhunterBaner.svg';
import sherlockBaner from 'assets/SherlockBaner.svg';
import breakingBadBaner from 'assets/BreakingBadBaner.svg';
import { useLocation } from 'react-router-dom';
const Background = () => {
const Location = useLocation();
let Baner;
if (Location.pathname == '/mindhunter') {
Baner = mindHunterBaner;
} else if (Location.pathname == '/sherlock') {
Baner = sherlockBaner;
} else if (Location.pathname == '/breakingbad') {
Baner = breakingBadBaner;
}
return (
<>
<div>
<img className="baner" src={Baner} alt="baner" />
</div>
</>
);
};
export default Background;

Related

Keep track of another components state

I have a bit of a basic React question that I am having trouble googling.
I have this component which is managing the state of maximize:
import React from 'react'
import { useState } from 'react';
import './Panel.scss'
import { AiFillExperiment, AiOutlineExpandAlt } from "react-icons/ai";
const Panel = ({title}) => {
const [maximize, setMaximize] = useState(false);
return (
<div className='panel'>
<AiFillExperiment />
<p>{title}</p>
<AiOutlineExpandAlt onClick={() => setMaximize(!maximize)} />
</div>
)
}
export default Panel
and this component that needs to be able to see the value of that state:
import './App.scss';
import { useEffect, useState } from 'react';
import ReactMarkdown from 'https://esm.sh/react-markdown#7'
import remarkBreaks from 'https://esm.sh/remark-breaks#3'
import Panel from './components/Panel'
function App() {
const [markdown, setMarkdown] = useState(``)
const placeholder =
`# Welcome to my React Markdown Previewer!
## This is a sub-heading...
### And here's some other cool stuff:
Here's some code, \`<div></div>\`, between 2 backticks.
\`\`\`
// this is multi-line code:
function anotherExample(firstLine, lastLine) {
if (firstLine == '\`\`\`' && lastLine == '\`\`\`') {
return multiLineCode;
}
}
\`\`\`
You can also make text **bold**... whoa!
Or _italic_.
Or... wait for it... **_both!_**
And feel free to go crazy ~~crossing stuff out~~.
There's also [links](https://www.freecodecamp.org), and
> Block Quotes!
And if you want to get really crazy, even tables:
Wild Header | Crazy Header | Another Header?
------------ | ------------- | -------------
Your content can | be here, and it | can be here....
And here. | Okay. | I think we get it.
- And of course there are lists.
- Some are bulleted.
- With different indentation levels.
- That look like this.
1. And there are numbered lists too.
1. Use just 1s if you want!
1. And last but not least, let's not forget embedded images:
![freeCodeCamp Logo](https://cdn.freecodecamp.org/testable-projects-fcc/images/fcc_secondary.svg)
`;
useEffect(() => {
setMarkdown(placeholder)
}, [placeholder])
return (
<div className="App">
{/* Editor Container */}
<div
className={'editor-container'}
>
<Panel title='Editor' />
<textarea id='editor' onChange={(e) => setMarkdown(e.target.value)} rows="" cols="">{placeholder}</textarea>
</div>
{/* Preview Container */}
<div className='preview-container'>
<Panel title='Preview' />
<div id='preview'>
<ReactMarkdown children={markdown} remarkPlugins={[remarkBreaks]} />
</div>
</div>
</div>
);
}
export default App;
How do I go about doing this? I realize I could have it all in one component, but I would like to know how to do it with two separate components.
Thanks in advance!
Through useState + props (less recommended)
You can do that by having that state in your App component and passing the setState as a property
const App = () => {
const [maximize, setMaximize] = useState(false);
const handleToggle = (newState) => {
setState(newState)
}
return (
<div>
<Panel toggleState={toggleState} maximize={maximize} />
</div>
)
}
And in your Panel component:
const Panel = ({toggleState, maximize}) => {
const handleToggle = () => {
toggleState(!maximize)
}
return (
<AiOutlineExpandAlt onClick={handleToggle} />
)
}
Through useContext hook
useContext allows you to store variables and access them on all child components within that context provider.
MaximizeProvider.js
import React, {useState, useContext} from "react";
//creating your contexts
const MaximizeContext = React.createContext();
const MaximizeUpdateContext = React.createContext();
// create a custom hook
export const useUpdate = () => {
return useContext(MaximizeUpdateContext)
}
export const useMaximize = () => {
return usecContext(MaximizeContext)
}
//creating your component that will wrap the child components
const MaximizeProvider = ({children}) => {
const [maximize, setMaximize] = useState(false)
// Your toggle to switch the state
const toggle = () => {
setMaximize(prevState => !prevState)
}
return (
<MaximizeContext.Provider value={maximize}>
<MaximizeUpdateContext.Provider value={toggle}>
{children}
</MaximizeUpdateContext.Provider>
</MaximizeContext.Provider>
)
}
export {MAximizeProvider}
Both providers allow you to access both the state and the setState
App.js
import React, {useState} from "react";
// your context component
import {MaximizeProvider} from "./MaximizeProvider";
// a button component
import {ButtonComponent} from "./ButtonComponent";
const App = () => {
return (
<>
<MaximizeProvider>
<ButtonComponent/>
</MaximizeProvider>
< />
);
}
export {App};
in the App, you are wrapping the elements that need your context.
as long as the elements and even children of children are in the wrap, it would have access to it the same way as in the button component.
ButtonComponent.js
import {useMaximize, useUpdate} from "./MaximizeProvider";
const ButtonComponent = () => {
const toggle = useUpdate();
const state = useMaximize()
return (
<button onClick={toggle}>Click</button>
);
}
export {ButtonComponent};
I hope this helps, I am not an expert, so there might be better ways to do it, but this seems to work for me.
Use redux or react context please,
props drilling is bad practice
https://reactjs.org/docs/context.html
https://redux.js.org/

Unable to seekTo or skip to time using <video> for MP4 files

I can't seem to be able to skip to a particular time using ReactPlayer.
Here's my code.
import React, { useRef } from "react";
import ReactPlayer from "react-player";
function VideoPlayer(props) {
const { video, setCurrTime, setAddComment } = props;
const playerRef = useRef();
const writeComments = () => {
if (playerRef.current) {
setCurrTime(playerRef.current.getCurrentTime());
setAddComment(true);
}
};
return (
<div className="player-wrapper">
<ReactPlayer
ref={playerRef}
className="react-player"
width="100%"
height="100%"
url={`http://127.0.0.1:8000${video.video}`}
controls
onPause={writeComments}
/>
</div>
);
}
export default VideoPlayer;
I suspect it might be the file format, MP4.
Unfortunately playerRef doesn't get set to a value you can use.
First caveat: https://github.com/cookpete/react-player/issues/1508
This is an open issue about React's StrictMode often enabled on new projects for React 18. It breaks setting src on the player so it doesn't work. If you upgrade to React 18, the simplest but not ideal solution is to disable React.StrictMode.
If your player is loading, you're on React 17 or you are not using StrictMode.
So if your video is loading, use ReactPlayer's onReady to set your playerRef. player passed into your onReady handler is the actual instance of ReactPlayer which has the methods you are looking for.
import React, { useRef } from "react";
import ReactPlayer from "react-player";
function VideoPlayer(props) {
const { video, setCurrTime, setAddComment } = props;
const playerRef = useRef();
const writeComments = () => {
if (playerRef.current) {
setCurrTime(playerRef.current.getCurrentTime());
setAddComment(true);
}
};
return (
<div className="player-wrapper">
<ReactPlayer
className="react-player"
width="100%"
height="100%"
url={`http://127.0.0.1:8000${video.video}`}
controls
onPause={writeComments}
onReady={(player) => playerRef.current = player}
/>
</div>
);
}
export default VideoPlayer;

Inserting Middleware(insights) with Instantsearch react

So, we have a functional search with Algolia/Instantsearch/React/Nextjs. But the Insights middleware is currently not setup.
Below is a trimmed version of the implementation, we use custom widgets to have more fine control over the display of results.
We use the hooks implementation for the custom widgets like so
const { hits, sendEvent, ... } = useInfiniteHits(props)
import { useState } from 'react'
import algoliasearch from 'algoliasearch/lite'
import { InstantSearch, InstantSearchSSRProvider } from 'react-instantsearch-hooks-web'
import SearchBox from '#components/swatches/algolia/SearchBox'
import Hits from '#components/swatches/algolia/Hits'
import RefinementList from '#components/swatches/algolia/RefinementList'
import CurrentRefinements from '#components/swatches/algolia/CurrentRefinements'
import { getServerState } from 'react-instantsearch-hooks-server'
import Container from 'react-bootstrap/Container'
import Row from 'react-bootstrap/Row'
import Col from 'react-bootstrap/Col'
import { history } from 'instantsearch.js/es/lib/routers/index.js'
import styles from '#styles/page.module.scss'
const Page = ({ serverState, url }) => {
const searchClient = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_INDEX_ID,
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY
)
return (
<div className={styles.wrapper}>
<InstantSearchSSRProvider {...serverState}>
<InstantSearch
searchClient={searchClient}
indexName={process.env.NEXT_PUBLIC_ALGOLIA_INDEX}
routing={{
router: history({
getLocation: () =>
typeof window === 'undefined' ? new URL(url) : window.location,
}),
}}
>
<Container fluid="lg">
<div className="mb-3">
<SearchBox />
</div>
<CurrentRefinements />
<Hits />
</Container>
</InstantSearch>
</InstantSearchSSRProvider>
</div>
)
}
export default Page
export async function getServerSideProps({ req, res, resolvedUrl}) {
const protocol = req.headers.referer?.split('://')[0] || 'https';
const url = `${protocol}://${req.headers.host}${req.url}`;
const serverState = await getServerState(<Page url={url} />);
return {
props: {
serverState,
url,
},
}
}
So my question is, where do we hook up the insights middleware for this specific implementation?
Reading the docs, (https://www.algolia.com/doc/api-reference/widgets/instantsearch/react-hooks/) I'm not really 100% sure where to start. I can't find anywhere in the instantsearch react docs where it references anyway to configure that sort of thing.
Am I better of just firing events at the API directly instead of with InstantSearch?
Thanks
The trick is finding the InstantSearch instance using useInstantSearch:
const instantSearch = useInstantSearch();
instantSearch.use(middleware)
The docs should tell you what to do from there.

Creating default chat groups in Sendbird using React

We've integrated a chat UI into a project using Sendbird. The chat interface is now working and what I am trying to do now is implement a feature where there are 2 default chat groups as shown in the mockup below:
I have already gone through the docs but I can’t seem to find the information I need to implement this feature. Can this be implemented? can someone guide me to the right direction, please?
import React, { useEffect, useState, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import { useSelector } from 'react-redux';
import 'sendbird-uikit/dist/index.css';
import { App as SendBirdApp, } from 'sendbird-uikit';
import { getModuleState as getAuthModuleState } from 'services/auth';
import colorSet from './styled/chatPalette';
import { Chat, ChatContainer, List } from './styled/chatPage';
import ChatGroups from './ChatGroups';
function ChatPage(props) {
const { theme } = props;
const history = useHistory();
const authState = useSelector(getAuthModuleState);
const userId = authState.username;
const nickname = authState.username;
const appId = authState.sendbirdData.appId;
const accessToken = authState.sendbirdData.accessToken;
useEffect(() => {
if (!userId || !nickname) {
console.error('Error, empty userId or nickname');
}
}, [userId, nickname, history]);
return (
<ChatContainer>
<SendBirdApp
appId={appId}
userId={userId}
nickname={nickname}
colorSet={colorSet}
/>
</ChatContainer>
);
}
export default ChatPage;
you can use the <SendbirdProvider> component and provide your custom channel preview component (let's say <ChannelPreview>) inside the <ChannelList> component.
Within your custom preview component (<ChannelPreview>) you can choose wether or not to show a specific channel based on its member count (channel.memberCount) as shown below:
import { Channel, ChannelList, SendBirdProvider } from 'sendbird-uikit';
import 'sendbird-uikit/dist/index.css';
import { useState } from 'react';
const CHANNEL_PREVIEW_MODES = [
'1-on-1',
'Group'
]
function ChannelPreview({channel, previewMode}) {
if (
(channel.memberCount <=2 && previewMode !== CHANNEL_PREVIEW_MODES[0]) ||
(channel.memberCount > 2 && previewMode !== CHANNEL_PREVIEW_MODES[1])
) {
return null
}
return (
<div key={channel.url}>
<img height="20px" width="20px" src={channel.coverUrl}/>
{channel.url}
</div>
)
}
function App() {
const [previewMode, setPreviewMode] = useState(CHANNEL_PREVIEW_MODES[0])
const [currentChannel, setCurrentChannel] = useState(null);
return (
<div className="App">
<SendBirdProvider
userId='<USER_ID>'
appId='<APP_ID>'
>
<div>
{CHANNEL_PREVIEW_MODES.map(mode =>
<label className="preview-mode-radio">{mode}
<input
type='radio'
value={mode}
name='preview-mode'
onChange={() => setPreviewMode(mode)}
checked={previewMode === mode}
/>
</label>
)}
</div>
<ChannelList
renderChannelPreview={({channel}) => <ChannelPreview channel={channel} previewMode={previewMode} />}
onChannelSelect={channel => setCurrentChannel(channel)}
/>
<Channel channelUrl={currentChannel?.url} />
</SendBirdProvider>
</div>
);
}
export default App;

Is this only possible with external URLs and not local?

I'm trying to make a photo gallery using react-images, the URLs are correct but the photos themselves are not loading into my web app. I get the broken image icon when switching themodalIsOpen:false to true.
Ive tried looking up examples of the same problems and alternatives, like if the component was configured right or if I am extending it right in the class.
import React, { Component } from 'react';
import Carousel, { Modal, ModalGateway } from 'react-images';
import blksmith from '../images/gallery/illustration/Blacksmith.jpg';
import mage from '../images/gallery/illustration/Mage.jpg';
const images =
[
{
src:{blksmith}
} ,
{
src:{mage}
}
];
class illuGallery extends Component {
state = { modalIsOpen: false }
toggleModal = () => {
this.setState(state => ({ modalIsOpen: !state.modalIsOpen }));
}
render() {
const { modalIsOpen } = this.state;
return (
<ModalGateway>
{modalIsOpen ? (
<Modal onClose={this.toggleModal}>
<Carousel
views={images}
/>
</Modal>
) : null}
</ModalGateway>
);
}
}
export default illuGallery;
This is in the actual gallery.js file, the web page that renders the gallery.
import React from 'react';
import Layout from "../components/layout";
import IlluPhotos from "../components/illustrationGallery";
import SEO from "../components/seo";
import './gallery.scss';
const GalleryPage = () => {
return (
<Layout>
<div style={{width:'100%',height:'250px'}}>
<SEO title="Gallery" />
<IlluPhotos/>
</div>
</Layout>
)
}
export default GalleryPage;
I am seeking some feedback on how to get this to work and what I did wrong, or what I should explore more.
So I ended up adding the pictures I wanted for the gallery to the public folder as mentioned farther down in this post
Since the https://localhost:8000 was appearing in front of the links to the images I wanted to use.
Thank you all for helping me find the answer!!
You don't need to import images.
According to react-images documentation, you just need to pass path to image as a string to <Carousel> component, like in this example below:
import React from 'react';
import Carousel from 'react-images';
const images = [{ src: 'path/to/image-1.jpg' }, { src: 'path/to/image-2.jpg' }];
class Component extends React.Component {
render() {
return <Carousel views={images} />;
}
}

Resources