Use Navigate function not working (React) - reactjs

I'm following a tutorial and everything was going great until I tried to implement Navigation through a search input. For instance, If I am on http://localhost:3000/searched/profile. Typing out an input of 'names' in the search bar should take me to http://localhost:3000/searched/names. In the tutorial it worked that way and I believe I did the same thing but it doesn't work for me
First below is the Search component for the search bar and its input
And then the Pages where my routing is done. My Browser Router is in the App.js.
import styled from "styled-components"
import { FaSearch } from 'react-icons/fa'
import { useState } from 'react'
import {useNavigate} from 'react-router-dom'
function Search() {
const [input, setInput] = useState('');
const navigate = useNavigate();
const submitHandler = (e) => {
e.preventDefault();
navigate('/searched/' + input) (I GUESS THIS IS WHAT IS NOT WORKING)
};
return (
<FormStyle onSubmit={submitHandler}>
<div>
<FaSearch></FaSearch>
<input onChange={(e) => setInput(e.target.value)} type="text" value={input}/>
</div>
<h1>{input}</h1>
</FormStyle>
)
}
const FormStyle = styled.div`
margin: 0 20rem;
div{
width: 100%;
position: relative;
}
input{
border: none;
background: linear-gradient(35deg, #494949, #313131);
border-radius: 1rem;
outline: none;
font-size: 1.5rem;
padding: 1rem 3rem;
color: white;
width: 100%;
}
svg{
position: absolute;
top: 50%;
left: 0%;
transform: translate(100%, -50%);
color: white;
}
`
export default Search
Pages
import Home from "./Home"
import { Route, Routes } from 'react-router-dom'
import Cuisine from "./Cuisine"
import Searched from "./Searched"
function Pages() {
return (
<Routes>
<Route path='/' element={<Home/>} />
<Route path='/cuisine/:type' element={<Cuisine/>} />
<Route path='/searched/:search' element={<Searched/>} />
</Routes>
)
}
export default Pages

The FormStyle component is a styled div element instead of a form element, so the onSubmit handler is meaningless on the div. To resolve you should use the form element so the form submission works as you are expecting.
Search.js Example:
import styled from "styled-components";
import { FaSearch } from "react-icons/fa";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
function Search() {
const [input, setInput] = useState("");
const navigate = useNavigate();
const submitHandler = (e) => {
e.preventDefault();
navigate("/searched/" + input);
};
return (
<FormStyle onSubmit={submitHandler}> // <-- (2) onSubmit works now
<div>
<FaSearch></FaSearch>
<input
onChange={(e) => setInput(e.target.value)}
type="text"
value={input}
/>
</div>
<h1>{input}</h1>
</FormStyle>
);
}
const FormStyle = styled.form` // <-- (1) switch to form element
margin: 0 20rem;
div {
width: 100%;
position: relative;
}
input {
border: none;
background: linear-gradient(35deg, #494949, #313131);
border-radius: 1rem;
outline: none;
font-size: 1.5rem;
padding: 1rem 3rem;
color: white;
width: 100%;
}
svg {
position: absolute;
top: 50%;
left: 0%;
transform: translate(100%, -50%);
color: white;
}
`;
export default Search;

Related

Uncaught (in promise) TypeError: n.indexOf is not a function at rt.fromString (index.esm2017.js:1032:1)

I was learning react and firebase but my app keeps showing this error and can't continue
Uncaught (in promise) TypeError: n.indexOf is not a function
at rt.fromString (index.esm2017.js:1032:1)
this is my code
import React, { useRef, useState } from 'react'
import styled from 'styled-components'
import { Button } from '#mui/material'
import { collection, doc,addDoc,serverTimestamp } from "firebase/firestore";
import { db } from '../firebase'
function ChatInput(chatName,channelId) {
const [input,setInput] = useState('')
console.log(channelId);
const sendMessage = async e =>{
e.preventDefault()
if(!channelId){
return false
}
const messageRef = doc(db, "rooms", channelId);
await addDoc(collection( messageRef,"messages"), {
message: input,
timestamp: serverTimestamp(),
user:'Abd',
userImage:'img'
});
setInput('')
}
return (
<ChatInputContainer>
<form>
<input value={input} onChange={e=>setInput(e.target.value)} placeholder={`Message #ROM`} />
<Button hidden type='submit' onClick={sendMessage}>
send
</Button>
</form>
</ChatInputContainer>
)
}
export default ChatInput
const ChatInputContainer = styled.div`
border-radius: 20px;
>form{
position: relative;
display: flex;
justify-content: center;
}
>form>input{
position: fixed;
bottom: 30px;
width: 60%;
border: 1px solid gray;
border-radius: 3px;
padding: 20px;
outline: none;
}
>form>button{
display: none !important;
}
`
if you need anything ask me
I tried updateDoc() setDoc() and many other answers from stack overflow

What is the reason why the pagination style is not getting applied? I am trying to display lists in row but it is not working

Pagination.jsx
import { Box } from "#chakra-ui/react";
import React, { useEffect, useState } from "react";
import ReactPaginate from "react-paginate";
import "./Pagination.css";
export function ReactPagination({ lastPage, filterData }) {
const [pageCount, setPageCount] = useState(0);
useEffect(() => {
setPageCount(lastPage);
}, [lastPage]);
// Invoke when user click to request another page.
const handlePageClick = (event) => {
filterData(event.selected + 1);
};
return (
<Box w="full">
<ReactPaginate
breakLabel="..."
nextLabel="next >"
onPageChange={handlePageClick}
pageRangeDisplayed={4}
pageCount={pageCount}
previousLabel="< previous"
renderOnZeroPageCount={null}
containerClassName="pagination"
previousLinkClassName="pagination__link"
nextLinkClassName="pagination__link"
disabledClassName="pagination__link--disabled"
activeClassName="pagination__link--active"
/>
</Box>
);
}
Pagination.css
//css for react paginate
.pagination {
list-style: none;
display: flex !important;
gap: 4px;
justify-content: space-between;
background: red;
}
.pagination a {
padding: 10px;
border-radius: 5px;
border: 1px solid #6c7ac9;
color: #6c7ac9;
}
.pagination__link {
font-weight: bold;
}
.pagination__link--active a {
color: #fff;
background: #6c7ac9;
}
.pagination__link--disabled a {
color: rgb(198, 197, 202);
border: 1px solid rgb(198, 197, 202);
}
The pagination className in containerClassName is not getting applied but it's strange that other styles like disabledClassName, activeClassName are applied. I am trying to display lists in row but it is not working. Is there any reason or any package updates that is causing this issue?

Passing a direction prop into styled-components keyframe component?

I'm trying to implement a reusable text animation component where a direction prop can be passed in. I probably close but doesn't seem to be working. Also open to better ways of implementing it a better way.
import React from "react"
import styled from "styled-components"
import { GlobalStyles } from "./global"
import TextAnimations from "./Components/TextAnimations"
const Container = styled.div`
display: flex;
justify-content: space-between;
flex-wrap: wrap;
`
const NavBar = styled.nav`
background: #3a3a55;
padding: 0.25rem;
width: 100%;
height: 10vh;
`
const Main = styled.main`
background: #3a3a55;
color: white;
padding: 0.25rem;
flex: 10 1 auto;
height: 100vh;
`
const Break = styled.div`
flex-basis: 100%;
width: 0;
`
function App() {
return (
<>
<GlobalStyles />
<Container>
<NavBar>NavBar</NavBar>
<Break />
<Main>
<TextAnimations text='Sample text from the left' direction='left' />
<TextAnimations text='Sample text from the right' direction='right' />
</Main>
</Container>
</>
)
}
export default App
and then the animation component:
import { motion } from "framer-motion"
import styled, { keyframes } from "styled-components"
type TextAnimationProps = {
text: string
direction: string
}
const Left = keyframes`
0% { left: -3.125em; }
100% { left: 3em;}
`
const Right = keyframes`
0% { Right: -3.125em; }
100% { Right: 3em;}
`
const HomeHeader = styled.div`
h1 {
font-weight: lighter;
}
position: relative;
top: 0;
animation: ${(props) => (props.defaultValue === "left" ? Left : Right)} // is this right?
animation-duration: 3s;
animation-fill-mode: forwards;
`
const TextAnimations = ({ text, direction }: TextAnimationProps) => {
return (
<HomeHeader defaultValue={direction}>
<h1>{text}</h1>
</HomeHeader>
)
}
export default TextAnimations
I'd also like to make it more flexible so that I can add 'top', 'bottom', etc.
Is this the best way to handle text animations?
You can create a separate function to set the animation. The function will receive the props of the styled component from which the function will access the direction prop.
const setHomeHeaderAnimation = ({ direction = "left" }) => {
const animation = keyframes`
0% {
${direction}: -3.125em;
}
100% {
${direction}: 3em;
}
`;
return css`
position: relative;
animation: ${animation};
animation-duration: 3s;
animation-fill-mode: forwards;
`;
};
const HomeHeader = styled.div`
${setHomeHeaderAnimation}
h1 {
font-weight: lighter;
}
`;
const App = () => (
<div>
<HomeHeader>
<div>Some text</div>
</HomeHeader>
<HomeHeader direction="right">
<div>Some text</div>
</HomeHeader>
<HomeHeader direction="top">
<div>Some text</div>
</HomeHeader>
<HomeHeader direction="bottom">
<div>Some text</div>
</HomeHeader>
</div>
);

How can React Js make a Border-botom as a function?

I would like to give Border-bottom as a function. What should I do?
This is the code that Border-bottom should appear.๐Ÿ‘‡
import React from "react";
import { Header } from "../BaseLabel";
import { Link, withRouter } from "react-router-dom";
const Header = ({ location: { pathname } }) => {
const getStyle = (path) => {
return {
color: pathname === path ? "#191919" : "#B6B6B6",
borderBottom: pathname === path ? "#191919" : null,
};
};
return (
<>
<ShapMenu>
<ShapLinks to="/covid19" style={getStyle("/covid19")}> //Link
<Header title="์ฝ”๋กœ๋‚˜19" current={pathname === "/covid19"} />
</ShapLinks>
</ShapMenu>
</>
);
}
This is Header Styled-components๐Ÿ‘‡
const ShapMenu = styled.div`
display: flex;
box-sizing: content-box;
overflow-x: scroll;
overflow-y: hidden;
white-space: nowrap;
scroll-behavior: smooth;
scrollbar-color: inherit;
cursor: pointer;
`;
const ShapLinks = styled(Link)``;
This is a reusable component code. This code is not only used on this screen because it is a reuse code.๐Ÿ‘‡
import PropTypes from "prop-types";
import styled from "styled-components";
import React from "react";
export const Header = ({ title, children }) => {
return (
<>
<Title>{title}</Title>
<Items>{children}</Items>
</>
);
};
Header.propTypes = {
title: PropTypes.node,
children: PropTypes.object,
};
const Items = styled.div``;
const Title = styled.div`
margin-right: 14px;
font-size: 20px;
`;
This is the style property that I want to give to the title.๐Ÿ‘‡
border-bottom: 2px solid
${(props) => (props.current ? "#191919" : "transparent")};
transition: border-bottom 0.5s ease-in-out;
The CSS styled rules appear to be correct. You should pass the current prop from Header to Title.
const Header = ({ current, title, children }) => { // <-- destructure current
return (
<>
<Title current={current}>{title}</Title> // <-- pass current prop
<Items>{children}</Items>
</>
);
};
Header.propTypes = {
children: PropTypes.object,
current: PropTypes.bool,
title: PropTypes.node
};
const Title = styled.div`
margin-right: 14px;
font-size: 20px;
border-bottom: 2px solid
${(props) => (props.current ? "#191919" : "transparent")}; // <-- use current prop
transition: border-bottom 0.5s ease-in-out;
`;

React Context API returns undefined

I'm quite new to React, and i'm trying to make a ToDoList. I have a Modal with a submit button that when pressed should add a ToDoItem. But since i didn't want to prop drill my way through this i wanted to use the Context API. The Context API confuses me quite a bit, maybe i'm just a moron, but i have a hard time understanding why i have to make a hook and pass that as the value in the provider. I thought that in the ToDoContext that i already defined the default value as a empty array, so i just did it again.
In the console at line 62, which is my initial render it says that it's undefined, after the pressing the Add ToDo I get the same message.
App.jsx
import React, { useState } from "react";
import { render } from "react-dom";
import { ThemeProvider } from "emotion-theming";
import { defaultTheme } from "./theme";
import { Global, css } from "#emotion/core";
import Header from "./components/Header";
import ToDoList from "./components/ToDoList";
import AddBtn from "./components/AddBtn";
import ToDoContext from "./ToDoContext";
const App = () => {
const [toDoItems] = useState([]);
return (
<>
{/*Global styling*/}
<Global
styles={css`
* {
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
text-decoration: none;
}
`}
/>
{/*App render start from here*/}
<ThemeProvider theme={defaultTheme}>
<ToDoContext.Provider value={toDoItems}>
<Header />
<main>
<ToDoList />
<AddBtn />
</main>
</ToDoContext.Provider>
</ThemeProvider>
</>
);
};
render(<App />, document.getElementById("root"));
ToDoContext.jsx
import { createContext } from "react";
const ToDoContext = createContext([[], () => {}]);
export default ToDoContext;
AddBtn.jsx
import React, { useState, useContext } from "react";
import { css } from "emotion";
import Modal from "../Modal";
import ToDoContext from "../ToDoContext";
const BtnStyle = css`
position: fixed;
bottom: 0;
right: 0;
cursor: pointer;
display: block;
font-size: 7rem;
`;
const ModalDiv = css`
position: fixed;
left: 50%;
background-color: #e6e6e6;
width: 60%;
padding: 20px 20px 100px 20px;
display: flex;
flex-direction: column;
align-items: center;
max-width: 400px;
height: 50%;
transform: translate(-50%, -50%);
border-radius: 20px;
top: 50%;
`;
const textareaStyle = css`
resize: none;
width: 100%;
height: 200px;
font-size: 1.25rem;
padding: 5px 10px;
`;
const timeStyle = css`
font-size: 3rem;
display: block;
`;
const modalSubmit = css`
width: 100%;
font-size: 3rem;
cursor: pointer;
margin-top: auto;
`;
const Label = css`
font-size: 2rem;
text-align: center;
display: inline-block;
margin-bottom: 50px;
`;
const AddBtn = () => {
const [showModal, setShowModal] = useState(true);
const [time, setTime] = useState("01:00");
const [toDoItems, setToDoItems] = useContext(ToDoContext);
console.log(toDoItems);
return (
<>
<div className={BtnStyle} onClick={() => setShowModal(!showModal)}>
<ion-icon name="add-circle-outline"></ion-icon>
</div>
{showModal ? (
<Modal>
<div className={ModalDiv}>
<div>
<label className={Label} htmlFor="time">
Time
<input
className={timeStyle}
type="time"
name="time"
value={time}
onChange={(e) => setTime(e.target.value)}
/>
</label>
</div>
<label className={Label} htmlFor="desc">
Description
<textarea
className={textareaStyle}
name="desc"
placeholder={`Notify yourself this message in ${time}`}
></textarea>
</label>
<button
className={modalSubmit}
onClick={() => {
setToDoItems(
toDoItems.push({
time,
})
);
}}
>
Add ToDo
</button>
</div>
</Modal>
) : null}
</>
);
};
export default AddBtn;
There are few issues in your code to fix:
useState returns a value and a setter. With this line of code, const [toDoItems] = useState([]);, you are just passing an empty array to your context.
So do this:
const toDoItems = useState([]);
In your ToDoContext.js, just pass an empty array as argument (initial value)
const ToDoContext = createContext([]);
Working copy of your code is here. (see console logs)
Also, I noticed that you are pushing the todo in setTodoItems in AddBtn.js.
Don't do this:
onClick={() => {
setToDoItems(
toDoItems.push({
time
})
);
}}
Do this:
onClick={() => {
setToDoItems(
toDoItems.concat([
{
time
}
])
);
}}

Resources