How to set a new song over current playing song react - reactjs

When I try to click a song after playing first both the songs play simultaneously instead pausing the first and playing second. Also there is an issue setting song name, stated in comments.
Playing.js
function Playing(props) {
const [song, setSong] = useState('SongName');
const [music, setMusic] = useState();
console.log(props.currentSong.song);
useEffect(() => {
if(typeof props.currentSong.song !== 'undefined') {
setSong(props.currentSong.song.song);
}else{
setSong('SongName'); //Also this Does not work if song state is set to ''
}
if(music){
console.log(music);
music.pause();
}
setMusic(new Audio(require(`./Songs/${song}.mp3`)));
}, [props.currentSong.song, song, setMusic]);
console.log(music);
const player = () => {
if (pauseToggle) {
music.pause();
} else {
music.play();
}
}
return (
<audio></audio>
<i
onClick={player}
className={pauseToggle ? "pause" : "play"}>
</i>
);
}
AllSong.js
function AllSong(props) {
return(
<Link
key={song.image}
to={{
pathname:"/",
state:{songInfo: song}
}}
onClick={() => props.setCurrentSong({song})}
>
<div>{song.song}</div>
</Link>
);
}
App.js
const [currentSong, setCurrentSong] = useState({});
return(
<Switch>
<Route
exact
path="/"
render={props => (
<Playing
{...props}
currentSong={currentSong}
/>
)}
/>
<Route
path="/AllSong"
render={props => (
<AllSong
{...props}
setCurrentSong={setCurrentSong}
/>
)}
/>
</Switch>
);
I also am learning the implementation on hooks so my code must look messy,
I really hope to get an answer from the community.

Related

React : Cycle life problem expected / redirect problem

For my first project with React, i tried to use useContext() for call my data mocked.
But after that, i have a problem.
The problem :
You go to a housing page, you change the apartment ID in the URL with a Dummy ID and you update it.
Great! The redirection to the 404 is done.
So you go back to the home page by clicking on the link of the 404.
You go back to any housing page => the 404 is always present.
You repeat, you then return to the home page and you click again on a housing card and WOW the problem no longer exists.
My Provider
import React, { useState, createContext } from "react"
import fetchLocationData from "../../services/localFetch"
export const FetchDataContext = createContext()
export const FetchDataProvider = ({ children }) => {
const [locationData, setLocationData] = useState({})
const [locationsData, setLocationsData] = useState([])
const [allLocationLoading, setAllLocationLoading] = useState(false)
const [isLocationLoading, setIsLocationLoading] = useState(false)
const [errorAPI, setErrorAPI] = useState(false)
const [error404, setError404] = useState(false)
async function fetchLocationById(locId) {
try {
setError404(false)
const response = await fetchLocationData.getLocById(locId)
response ? setLocationData(response) : setError404(true)
} catch (err) {
console.log(err)
setErrorAPI(true)
} finally {
setIsLocationLoading(true)
console.log("in provider :", error404)
}
}
async function fetchAllLocations() {
try {
const response = await fetchLocationData.getAll()
setLocationsData(response)
} catch (err) {
console.log(err)
setErrorAPI(true)
} finally {
setAllLocationLoading(true)
}
}
return (
<FetchDataContext.Provider
value={{
errorAPI,
error404,
isLocationLoading,
allLocationLoading,
locationData,
locationsData,
fetchLocationById,
fetchAllLocations,
}}
>
{children}
</FetchDataContext.Provider>
)
}
My router
function App() {
return (
<>
<GlobalStyle />
<BlocPage>
<Header />
<FetchDataProvider>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/apartment/:locId" element={<ProfileLocation />} />
<Route path="*" element={<Error />} />
</Routes>
</FetchDataProvider>
</BlocPage>
<Footer />
</>
)
}
My housing page
function ProfileLocation() {
const { locId } = useParams()
const {
errorAPI,
error404,
locationData,
isLocationLoading,
fetchLocationById,
} = useContext(FetchDataContext)
useEffect(() => {
fetchLocationById(locId)
}, [])
const rating = parseInt(locationData.rating)
if (errorAPI) {
return (
<span>
Oups une erreur est survenue ... Veuillez recommencer ultérieurement.
</span>
)
}
if (error404) {
return <Navigate to="/error404" />
}
return (
<div>
{isLocationLoading ? (
<>
<Slider pictures={locationData.pictures} />
<ResponsiveWrapper>
<FirstSectionWrapper>
<Title>{locationData.title}</Title>
<Geolocation>{locationData.location}</Geolocation>
<TagsWrapper>
{locationData.tags.map((tag, index) => (
// eslint-disable-next-line react/no-array-index-key
<Tag key={`${tag}-${index}`} label={tag} />
))}
</TagsWrapper>
</FirstSectionWrapper>
<SecondSectionWrapper>
<OwnerWrapper>
<HomeOwnerName>{locationData.host.name}</HomeOwnerName>
<HomeOwerPicture
src={locationData.host.picture}
alt={locationData.host.name}
/>
</OwnerWrapper>
<StarsWrapper>
<StarScale ratingValue={rating} starType="full" />
<StarScale ratingValue={rating} starType="empty" />
</StarsWrapper>
</SecondSectionWrapper>
</ResponsiveWrapper>
<CollapseSectionWrapper>
<CollapseWrapper>
<Collapse
pageType="profil"
label="Description"
contentType="paragraph"
contentText={locationData.description}
/>
</CollapseWrapper>
<CollapseWrapper>
<Collapse
pageType="profil"
label="Équipements"
contentType="list"
contentText={locationData.equipments}
/>
</CollapseWrapper>
</CollapseSectionWrapper>
</>
) : (
<Loader />
)}
</div>
)
}
export default ProfileLocation
Maybe it’s an async code problem?
The issue is that only navigating forward to a route rendering a component that calls fetchLocationById will ever manage to clear/set the error404 state back to false.
I suggest instead of passing error404 back to the components that the FetchDataProvider handles rendering the error UI upon the error condition. Having it redirect to a specific error page.
Example:
<FetchDataProvider>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/apartment/:locId" element={<ProfileLocation />} />
<Route path="/404" element={<Error404 />} /> // <-- add route
<Route path="*" element={<Error />} />
</Routes>
</FetchDataProvider>
...
const Error404 = () => (
<div>Oups une erreur est survenue ... Veuillez recommencer ultérieurement.</div>
);
...
import { useNavigate } from 'react-router-dom';
export const FetchDataProvider = ({ children }) => {
const navigate = useNavigate();
...
async function fetchLocationById(locId) {
try {
setError404(false)
const response = await fetchLocationData.getLocById(locId)
if (response) {
setLocationData(response);
} else {
navigate("/error404", { replace: true });
}
} catch (err) {
navigate("/error404", { replace: true });
} finally {
setIsLocationLoading(true);
}
}
...
return (
...
);
}
...
function ProfileLocation() {
const { locId } = useParams();
const {
locationData,
isLocationLoading,
fetchLocationById,
} = useContext(FetchDataContext);
useEffect(() => {
fetchLocationById(locId);
}, [fetchLocationById, locId]); // <-- don't forget to add proper dependencies
const rating = parseInt(locationData.rating);
return (
<div>
{isLocationLoading ? (
<>
<Slider pictures={locationData.pictures} />
<ResponsiveWrapper>
<FirstSectionWrapper>
<Title>{locationData.title}</Title>
<Geolocation>{locationData.location}</Geolocation>
<TagsWrapper>
{locationData.tags.map((tag, index) => (
// eslint-disable-next-line react/no-array-index-key
<Tag key={`${tag}-${index}`} label={tag} />
))}
</TagsWrapper>
</FirstSectionWrapper>
<SecondSectionWrapper>
<OwnerWrapper>
<HomeOwnerName>{locationData.host.name}</HomeOwnerName>
<HomeOwerPicture
src={locationData.host.picture}
alt={locationData.host.name}
/>
</OwnerWrapper>
<StarsWrapper>
<StarScale ratingValue={rating} starType="full" />
<StarScale ratingValue={rating} starType="empty" />
</StarsWrapper>
</SecondSectionWrapper>
</ResponsiveWrapper>
<CollapseSectionWrapper>
<CollapseWrapper>
<Collapse
pageType="profil"
label="Description"
contentType="paragraph"
contentText={locationData.description}
/>
</CollapseWrapper>
<CollapseWrapper>
<Collapse
pageType="profil"
label="Équipements"
contentType="list"
contentText={locationData.equipments}
/>
</CollapseWrapper>
</CollapseSectionWrapper>
</>
) : (
<Loader />
)}
</div>
);
}

Where to call http requests regarding optimization in React

I have an axios request that allows me to get user information if he's logged and display it on his profile page.
My question is where to call it to avoid too many request and enhance optimization.
I've seen people calling it on top in App.js but I find it weird. I'm currently calling it in my container component that render UserProfile or LogForm depending if user is logged, but then a request is made each time user clicks on his profile page and I don't feel that it is the right way.
Here is my code:
Profile.tsx
const Profile = () => {
const dispatch = useDispatch();
const userId = useSelector((kinaccess: RootStateOrAny) => kinaccess.formsReducer.signInForm.success.userId);
useEffect(() => {
dispatch(Action.getUserInfo(userId));
}, [userId, dispatch]);
return <div>{userId ? <UserProfile /> : <LogForm />}</div>;
};
UserProfile.tsx
const UserProfile = () => {
const userInfo = useSelector((kinnacess: RootStateOrAny) => kinnacess.userReducer.user.success);
if (!userInfo) return null;
const { name, firstName, email } = userInfo;
return (
<section className='user-profile'>
<h3>
Hello {firstName} {name}
</h3>
<p>Is your mail adress still {email}</p>
</section>
);
};
An my Routes.tsx
const Routes = () => {
return (
<Routing>
<Route index element={<Home />} />
<Route path='contact' element={<ContactForm />} />
<Route path='profile' element={<Profile />} />
<Route path='*' element={<Error404 />} />
</Routing>
);
};

Detail Image Rendering in React

When I tried to image, image is broken
BASE_URL I want to fetch is composed like this.
{
"renderings": [
{
"_id": "image_file"(string type)
},
...more _id
}
This is a similar topic to the question I posted a few days ago.
But I see the problem seems to arise while implementing the detail page.
// App.tsx
function App() {
return (
<BrowserRouter>
<Route exact path="/">
<Gallery />
</Route>
<Route path="/detail">
<Detail />
</Route>
</BrowserRouter>
);
}
export default App;
// Gallery.tsx
function Gallery() {
const [gallery, setGallery] = useState<any>();
const getGallery = async () => {
const json: GalleriesProps = await (await fetch(BASE_URL)).json();
setGallery(json.renderings);
};
useEffect(() => {
getGallery();
}, []);
return (
<ImgContainer>
<Link to="/detail">
{gallery &&
gallery.map((x: any) => (
<img key={x._id} alt="gallery_logo" src={x._id} />
))}
</Link>
</ImgContainer>
);
}
export default Gallery;
// Detail.tsx
function Detail() {
const [galleryDetail, setGalleryDetail] = useState<any>();
const [clicked, setClicked] = useState(false);
console.log(galleryDetail);
useEffect(() => {
async function fetchGallery() {
const response = await fetch(BASE_URL);
const result: GalleriesProps = await response.json();
setGalleryDetail(result.renderings[0]._id);
}
fetchGallery();
}, []);
const prevPage = () => {
if (clicked) return;
setClicked(true);
};
const nextPage = () => {
if (clicked) return;
setClicked(true);
};
return (
<>
<Container>
<Button onClick={prevPage}>
<FontAwesomeIcon icon={faArrowAltCircleLeft} />
</Button>
<ImageDetail>
{galleryDetail && <img src={galleryDetail} />}
</ImageDetail>
<Button onClick={nextPage}>
<FontAwesomeIcon icon={faArrowAltCircleRight} />
</Button>
</Container>
</>
);
}
export default Detail;
When I click on an image, I go to the detail page, and then I have to implement that image to show,
For example,
If I click the image of the cat.jpeg file, I have to go to the detail page and change the size of cat.jpeg and show the rest as it is,
but I can't quite figure it out.

React Hooks: Component is not rendering in Nested Routing

I am using "react-scripts": "4.0.2" and all my components are React Hooks. My logic involves nested routing but the end result is not rendered.
App.js:
<BrowserRouter>
<div className="App">
<TopNav />
<Home />
</div>
</BrowserRouter>
Home.js:
<Switch>
<Route path="/" component={Questions} />
</Switch>
Questions.js
const displayQuestion = (qid) => {
props.history.push({ pathname: "/question/" + qid });
};
//questions is an array of objects
const questionsBlocks = questions.map((quest, i) => {
return (
<QBlock
key={i + 1}
qno={i + 1}
displayQuestion={displayQuestion.bind(this, quest.qid)}
/>
);
});
return (
<div>
<h1>Questions</h1>
{questionsBlocks}
<Switch>
<Route
path="/question/:id"
render={(props) => <Question {...props} questions={questions} />}
/>
</Switch>
</div>
);
QBlock will only render buttons that will call displayQuestion on being clicked
QBlock.js:
return (
<div className="block" onClick={props.displayQuestion}>
<h1>{props.qno}</h1>
</div>
);
Question.js:
const [question, setQuestion] = useState();
const loadQuestion = () => {
console.log(props);
if (props.match.params.id) {
console.log("load called");
const qid = props.match.params.id;
const index = props.questions.findIndex((quest) => quest.qid == qid);
setQuestion(props.questions[index]);
}
};
// componentDidMount with react hooks
useEffect(() => {
console.log("Mounted");
loadQuestion();
}, []);
// componentDidUpdate with react hooks
useEffect(() => {
console.log("Updated");
loadQuestion();
}, [props.match.params.id]); //Even tried with only props
return (
<div className="Quest">
<div className="question">{question.question}</div>
<div className="options">{question.answerChoices}</div>
</div>
);
Neither of the useEffect of Question.js is not executing still I am getting the following error.
Basically, question needs to be initialized
const [question, setQuestion] = useState(null);
And another thing you need to do is to check the value of question before using it
return (
<div className="Quest">
{question && question.question && <div className="question">{question.question}</div>}
{question && question.answerChoices && <div className="options">{question.answerChoices}</div>}
</div>
);
As Vince said.. I had defined useState like const [question, setQuestion] = useState(); instead of const [question, setQuestion] = useState({});

Can't display the output of a search on another component

Im having problems at the result component i can't render the filteredData, at result this.props.dataToRender ain't working thats the problem.
I have all the logic already, but when trying to display the result of the search on another component i'm getting no information.
If i execute the code on the app component i get the result of the search but if i try to pass it as props i don't get a result at the other side.
state = { data: [], filteredData: [], value: "" };
async componentDidMount() {
axios
.get("https://tenjoucesar.github.io/data.json")
.then(response => response.data)
.then(data => {
this.setState({ data });
console.log(this.state.data);
});
}
handleSubmit(e) {
const { value, data } = this.state;
e.preventDefault();
let email = value;
const filtered = data.filter(e => e.email === email);
this.setState({ filteredData: filtered });
}
handleChange(e) {
this.setState({ value: e.target.value });
}
InfomData = person => {
return (
<div className="result" key={person.email}>
<h3 >
{person.name}, {person.age}
</h3>
<p className="paragraph--result">{person.notes}</p>
</div>
);
};
render() {
const { filteredData } = this.state;
const dataToRender = filteredData.map(e => this.InfomData(e));
return (
<React.Fragment>
<Nav />
<Switch>
<>
<Route exact path="/" component={Header} />
<Search
component={Search}
handleSubmit={this.handleSubmit.bind(this)}
handleChange={this.handleChange.bind(this)}
value={this.props.value}
type={this.props.email}
/>
<Route exact path="/" component={Reverse} />
<Route
path="/result"
component={Result}
dataToRender={dataToRender}
/>
</>
</Switch>
<Footer />
</React.Fragment>
);
}
}
Here at Result component i tried moving informData and the const dataToRender but didn't work.
class Result extends Component {
render() {
return (
<div className="section-result">
<div className="container--result">
<h1 className="heading-primary--result">Results</h1>
<p className="paragraph--results">
Look at the result below to see the details of the person you're
searched for.
</p>
</div>
{this.props.dataToRender}
<TryAgain />
</div>
);
}
}
I just want to get the result on the result component, i had tried with all that i found, nothing worked.
Could someone tell me what do i have to do ? I'm sorry still learning about react
Just Modify the Route to this
<Route
path="/result"
render={() => <Result dataToRender={dataToRender} />}
/>
Since you have to inject props to a component, this is the way
Pass Route's render an arrow function with component and customProps
EDIT
If you also need the history, location, search props that are passed by default when we use <Route path="/" component={Something} /> then pass them explicitly
<Route
path="/result"
render = {(props) => <Result dataToRender={dataToRender} {...props} /> }
/>

Resources