I am working on Reactjs and using nextjs framework,Right now i want if url containing "?id=pinned" then different text should display,How can i do this ? Here is my current code in [slug.js]
return(
if(url containing pinned)
{
<div id="neww" className="neww"><h3>Pinned</h3></div>
}
else
{
<div id="neww" className="neww"><h3>Newest</h3></div>
}
)
Since it seems like you're using Next.js, you can use Next.js API to do this
import { useRouter } from 'next/router'
const Post = () => {
const router = useRouter()
const { id } = router.query
const isPinned = id === 'pinned'
if (isPinned) {
return (<div id="neww" className="neww"><h3>Pinned</h3></div>)
} else {
return (<div id="neww" className="neww"><h3>Newest</h3></div>)
}
}
Do this:
import { useRouter } from 'next/router'
const Post = () => {
const {query} = useRouter()
const isPinned = query.id === 'pinned'
return (<div id="neww" className="neww">
<h3>{isPinned ? 'Pinned': 'Newest'}</h3>
</div>)
}
ignore if else, you should try the ternary operator
return(
<div id="neww" className="neww">
<h3>
{(url.includes('pinned') ? "Pinned":"Newest" }
</h3>
</div>
)
You can use the query from router
Example
const router = useRouter();
const {id} = router.query;
return(
if(id === "pinned")
{
<div id="neww" className="neww"><h3>Pinned</h3></div>
}
else
{
<div id="neww" className="neww"><h3>Newest</h3></div>
}
)
Here is a way:
import { useRouter } from "next/router";
const router = useRouter();
const id = router.query["id"];
return(
if(id === "pinned")
{
<div id="neww" className="neww"><h3>Pinned</h3></div>
}
else
{
<div id="neww" className="neww"><h3>Newest</h3></div>
}
)
Related
I am making a simple messaging app, when i try to send messages the same div gets updated with new message but a new div does not get added. i was using index first while mapping the messages to display but it did not work so i added a msgId to the messages and tried to use it as the key but it's still not working
this is OpenConversation.js
import React, { useState } from 'react'
import {Button, Form, InputGroup, ListGroup} from 'react-bootstrap'
import { useConversations } from '../contexts/ConversationsProvider'
export default function OpenConversation() {
const[text,setText]=useState()
const {sendMessage,selectedConversation}=useConversations()
function handleSubmit(e) {
e.preventDefault()
console.log("index",selectedConversation)
sendMessage(
selectedConversation.recipients.map(r => r.id),
text
)
setText('')
}
return (
<div className="d-flex flex-column flex-grow-1">
<div className="flex-grow-1 overflow-auto">
<div className="d-flex flex-column align-items-start justify-content-end px-3">
{selectedConversation.messages.map((message) => {
return (
<div
key={message.msgId}
className={`my-1 d-flex flex-column ${message.fromMe ? 'align-self-end align-items-end' : 'align-items-start'}`}
>
<div
className={`rounded px-2 py-1 ${message.fromMe ? 'bg-primary text-white' : 'border'}`}>
{message.text} {message.msgId}
</div>
<div className={`text-muted small ${message.fromMe ? 'text-right' : ''}`}>
{message.fromMe ? 'You' : message.senderName}
</div>
</div>
)
})}
</div>
</div>
<Form style={{position:'absolute',bottom:'0rem'}}
onSubmit={handleSubmit}
>
<Form.Group className='m-2'>
<InputGroup >
<Form.Control as='textarea' required
value={text}
onChange={e=>setText(e.target.value)}
style={{height:'75PX',resize:'none',}}
/>
<Button type="submit" style={{background:'#7c73e6',border:'none'}}>Send</Button>
</InputGroup>
</Form.Group>
</Form>
</div>
)
}
ConversationsProvider.js
import React, { useContext, useState, useEffect, useCallback } from 'react'
import useLocalStorage from '../hooks/useLocalStorage';
import { useContacts } from './ContactsProvider';
import {v4 as uuidv4} from 'uuid'
const ConversationsContext = React.createContext()
export function useConversations() {
return useContext(ConversationsContext)
}
export default function ConversationsProvider({ id, children }) {
const [conversations, setConversations] = useLocalStorage('conversations', [])
const [selectedConversationIndex,setSelectedConversationIndex]=useState(0)
const { contacts } = useContacts()
function createConversation(recipients) {
setConversations(prevConversations => {
return [...prevConversations, { recipients, messages: [] }]
})
}
function selectConversationIndex(i)
{
setSelectedConversationIndex(i)
}
function addMessageToConversation({recipients,text,sender})
{
setConversations(prevConversations=>{
let madeChange=false
let msgId=uuidv4()
const newMessage={sender,text,msgId}
const newConversations=prevConversations.map(conversation=>{
if(arrayEquality(conversation.recipients,recipients))
{
madeChange=true
return{
...conversation,
messages:[conversation.messages,newMessage]
}
}
return conversation
})
if(madeChange){
return newConversations
}
else{
return [...prevConversations,{recipients,messages:[newMessage]}]
}
})
console.log(conversations)
}
function sendMessage(recipients,text)
{ console.log("working")
addMessageToConversation({recipients,text,sender:id})
}
const formattedConversations = conversations.map((conversation, index) => {
const recipients = conversation.recipients.map(recipient => {
const contact = contacts.find(contact => {
return contact.id === recipient
})
const name = (contact && contact.name) || recipient
return { id: recipient, name }
})
const messages = conversation.messages.map(message => {
const contact = contacts.find(contact => {
return contact.id === message.sender
})
const name = (contact && contact.name) || message.sender
const fromMe = id === message.sender
return { ...message, senderName: name, fromMe }
})
const selected = index === selectedConversationIndex
return { ...conversation, messages, recipients, selected }
})
const value = {
conversations: formattedConversations,
selectedConversation: formattedConversations[selectedConversationIndex],
sendMessage,
selectConversationIndex: setSelectedConversationIndex,
createConversation
}
return (
<ConversationsContext.Provider value={value}>
{children}
</ConversationsContext.Provider>
)
}
function arrayEquality(a, b) {
console.log("working")
if (a.length !== b.length) return false
a.sort()
b.sort()
return a.every((element, index) => {
return element === b[index]
})
}
i did not understand why index did not work, is there another way to map the messages?
Your error comes from this line
messages:[conversation.messages,newMessage]
in the addMessageToConversation function
I think you need to spread conversation.messages.
Change [conversation.messages, newMessage] to [...conversation.messages, newMessage].
With what you're doing currently, you're making the previous messages object, the first item in the array and then the new one as the second item.
I am trying to pass a function from a parent to child component to have the child change the parents state. Basically I have a search bar that needs to change what is displayed on the main page.
When I check the type of the function in the parent it shows up as a function but when I send and check it in the child its type is undefined. I get an error that its not a function whenever I try to call it in the child component
import LineChart from "./charts/LineChart";
import React, { Component } from 'react';
import Player from "../Components/Player";
import SearchBar from '../Components/SearchBar';
class Future extends Component {
state = {
players: [],
data: [],
playerID : ""
};
async componentDidMount() {
if (Player.playerID == "") {
const response = await fetch('http://localhost:8080/random');
const body = await response.json();
this.setState({ players: body });
console.log(body[0].player_id);
this.setState({ playerID: body[0].player_id })
this.setData(body[0].player_id)
} else {
this.displayPlayer(Player.playerID)
this.setData(Player.playerID)
}
}
async displayPlayer(playerID) {
if (playerID != "") {
const response = await fetch('http://localhost:8080/get_player/' + playerID);
const body = await response.json();
this.setState({ players: body });
}
}
onSearchChange = (value) => {
this.setState({ playerID: value });
}
async setData(id) {
const response = await fetch('http://localhost:8080/goal_prediction/' + id);
const body = await response.json();
this.setState({ data: body });
console.log(body);
}
render() {
this.displayPlayer(Player.playerID)
const { players, data, id } = this.state;
return (
<div>
<SearchBar placeholder={"Search"} stateChange={this.onSearchChange} />
{players.map(player =>
<div key={player.id}>
{player.name}'s goals
</div>
)}
<LineChart />
Goals predicted for next season: {data.predicted_goals }
</div>
);
}
}
export default Future;
import './SearchBar.css';
import React, { useState } from 'react';
import CloseIcon from '#mui/icons-material/Close';
import SearchIcon from '#mui/icons-material/Search';
import Player from '../Components/Player';
import Future from '../pages/FutureStats';
function SearchBar({ placeholder }, { stateChange }) {
const [filteredData, setFilteredData] = useState([]);
const [wordEntered, setWordEntered] = useState("");
const handleFilter = async (event) => {
const searchWord = event.target.value // Access the value inside input
setWordEntered(searchWord);
const url = 'http://localhost:8080/search_player/' + searchWord;
const response = await fetch(url);
const body = await response.json();
if (searchWord === "") {
setFilteredData([])
} else {
setFilteredData(body);
}
}
const clearInput = () => {
setFilteredData([]);
setWordEntered("");
}
const selectInput = value => () => {
console.log(Player.playerID)
Player.playerID
setFilteredData([]);
setWordEntered("");
console.log(typeof(stateChange))
stateChange(value);
}
return (
<div className='search'>
<div className='searchInputs'>
<input type={"text"} value={wordEntered} placeholder={placeholder} onChange={handleFilter} />
<div className='searchIcon'>
{filteredData.length === 0 ? <SearchIcon/> : <CloseIcon id="clearButton" onClick={clearInput} />}
</div>
</div>
{filteredData.length !== 0 && (
<div className='dataResult'>
{filteredData.slice(0, 15).map((value) => {
return (
// Stay on one page.
<a className="dataItem" target="_blank" rel="noopener noreferrer" onClick={selectInput(value.player_id)}>
<p key={value.id}>{value.name}</p>
</a>
);
})}
</div>
)}
</div>
);
}
export default SearchBar;
stateChange is part of your props and needs to be the first argument in your SearchBar function:
function SearchBar({ placeholder, stateChange }) {
...
I currently have a <textarea/> field that when you press enter it submits and makes a new item on the array. When you press shift + enter it creates a new line in the <textarea/> input field.
However, when you actually press shift and enter to make a new break and submit it; it does not recognize the break in the line. I have attached images below.
As you can see above, its like the array does not recognize there is a break in the input.
Todobox.jsx:
import React, { createContext } from 'react';
import Item from './Item';
import { useState, useContext } from 'react';
import '../App.css';
import trash from '../trash_can.png'
import { ElementContext } from '../ElementContext';
export const ItemContext = createContext();
export const ItemContextProvider = ({ children }) => {
const [items, setItems] = useState([]);
const [itemId, setItemId] = useState(1);
const [itemData, setItemData] = useState();
const [refDict, setRefDict] = useState({});
const newItemId = (items) =>{
setItemId(itemId + 1);
console.log(itemId)
}
const newItem = (itemChange, boxid) => {
newItemId();
if (!refDict[itemId]) {
setItems(prev => [...prev, { itemboxid: boxid, itemdata: itemChange, itemid: itemId }]);
setRefDict((prev) => ({...prev, [itemId]: true}));
}
console.log(items);
};
const value = {
items,
setItems,
newItem,
itemId
};
return(
<ItemContext.Provider value={value}>
{children}
</ItemContext.Provider>
)
};
export default function Todobox({ boxtitle, boxid }){
const { elements, setElements, newTitle } = useContext(ElementContext);
const { items, setItems, newItem } = useContext(ItemContext);
const [boxheader, setBoxHeader] = useState('');
const [itemChange, setItemChange] = useState('');
const handleChange = (e) => {
setBoxHeader(e.target.value);
}
const handleKeydown = (e) => {
if(e.keyCode == 13 && e.shiftKey == false){
setElements(elements.map(element => {
if (element.boxid === boxid) {
setBoxHeader(e.target.value)
return { ...element, boxtitle: boxheader };
} else {
return element;
}
}))
e.preventDefault();
alert('Title has been set to: ' + boxheader);
}
}
const handleDelete = (e) => {
setElements(elements.filter(element => element.boxid !== boxid))
}
const handleItemChange = (e) =>{
setItemChange(e.target.value);
}
const handleNewItem = (e) =>{
if(e.keyCode == 13 && e.shiftKey == false){
newItem(itemChange, boxid)
e.preventDefault();
e.target.value = '';
}
}
return(
<>
<div className='element-box'>
<img src={trash} className='element-box-trash' onClick={handleDelete}></img>
<textarea className='element-title-input' placeholder='Add title...' onChange={handleChange} onKeyDown={handleKeydown} value={boxheader}></textarea>
{items.map(item => {
if(item.itemboxid === boxid){
return <Item key={item.itemid} itemid={item.itemid} itemdata={item.itemdata}/>;
} else if(item.itemboxid !== boxid){
return null;
}
})}
<textarea
className='element-input'
type='text'
placeholder={`Add item... ${boxid}`}
onChange={handleItemChange}
onKeyDown={handleNewItem}
onClick={() => {console.log(boxid)}}
/>
</div>
</>
)
}
Item.jsx:
import React, { useContext } from 'react';
import '../App.css';
import { ElementContext } from '../ElementContext';
import { ItemContext } from './Todobox';
export default function Item({ itemid, itemdata }){
const { setHideModal, modals, setModals } = useContext(ElementContext);
const handleNewModal = () => {
setHideModal(false)
setModals(prev => [...prev, { modalItemId: itemid, modalId: '1', modalData: itemdata }]);
console.log(modals);
};
return(
<div className='item-container' onClick={handleNewModal}>
<a className='item-text'>{itemdata}</a>
</div>
)
}
Item-input css:
.item-text {
padding: 2px;
opacity: 1;
word-wrap: break-word;
}
Any help would be appreciated, thank you in advanced! :)
#caTS answered my question in a comment.
I had to add white-space: pre-wrap to my CSS.
I am trying to toggle view between list of meals and meal details. I have placed a button in the child component Meal.js to the Meals.js which is meant to be the list and the details view.
Can you please help me fix this issue. Seems like its not working even with the conditional rendering method I've used in the code below.
Meal.js
import { useState } from 'react'
import './Meal.css'
const Meal = (props) => {
const [isToggled, setIsToggled] = useState(false);
const sendIdHandler = () => {
if (isToggled === true) {
setIsToggled(false);
}
else {
setIsToggled(true);
}
props.onSaveIdHandler(props.id, isToggled)
}
return (
<div
className='meal'
onClick={sendIdHandler}
>
{props.label}
</div>
);
}
export default Meal;
Meals.js
import Meal from './Meal/Meal'
const Meals = (props) => {
let toggleCondition = false;
const saveIdHandler = (data, isToggled) => {
toggleCondition = isToggled;
const mealDetails = props.mealsMenuData.findIndex(i =>
i.id === data
)
console.log(mealDetails, toggleCondition)
}
return (
<div>
{toggleCondition === false &&
props.mealsMenuData.map(item =>
<Meal
key={item.id}
id={item.id}
label={item.label}
onSaveIdHandler={saveIdHandler}
/>
)
}
{toggleCondition === true &&
<div>Horray!</div>
}
</div>
);
}
export default Meals;
UPDATE
Finally figured how to do this properly. I put the condition true/false useState in the parent instead and have Meal.js only send the id I need to view the item
Code is below..
Meals.js
import { useState } from 'react'
import Meal from './Meal/Meal'
import MealDetails from './MealDetails/MealDetails'
const Meals = (props) => {
const [show, setShow] = useState(false);
const [mealId, setMealId] = useState(0);
const saveIdHandler = (data) => {
setShow(true);
setMealId(props.mealsMenuData.findIndex(i =>
i.id === data)
)
console.log(props.mealsMenuData[mealId].ingridients)
}
const backHandler = () => {
setShow(false)
}
return (
<div>
{show === false &&
props.mealsMenuData.map(item =>
<Meal
key={item.id}
id={item.id}
label={item.label}
onSaveIdHandler={saveIdHandler}
/>
)
}
{show === true &&
<div>
<MealDetails data={props.mealsMenuData[mealId]} />
<button onClick={backHandler}>Back</button>
</div>
}
</div>
);
}
export default Meals;
Meal.js
import './Meal.css'
const Meal = (props) => {
const sendIdHandler = () => {
props.onSaveIdHandler(props.id)
}
return (
<div
className='meal'
onClick={sendIdHandler}
>
{props.label}
</div>
);
}
export default Meal;
Your problem in sendIdHandler: You can update like this:
const sendIdHandler = () => {
const newIsToggled = !isToggled;
setIsToggled(newIsToggled)
props.onSaveIdHandler(props.id, newIsToggled)
}
If a user is selected from the list, the boolean is true, when the selected user is unselected from the list, the boolean is false. The boolean will remain true if another user is selected from the list.
Here's my code:
import React, { useEffect, useState } from "react";
import "./styles.css";
import Users from "./Users";
export default function UserApp() {
const [ selectUser, setSelectUser ] = useState(null);
const [ isUserSelected, setIsUserSelected ] = useState(false);
const handleUserClick = (user) => {
setSelectUser((prev) => (
user !== prev ? user : null
))
if(selectUser === null) {
setIsUserSelected(!isUserSelected)
} else {
setIsUserSelected(isUserSelected)
}
}
console.log(selectUser);
console.log(isUserSelected);
return (
<div className="App">
<Users selectedUser={handleUserClick} />
</div>
);
}
Update your if statement:
if(selectUser !== null) {
setIsUserSelected(true)
} else {
setIsUserSelected(false)
}
OR:
if(selectUser === null) {
setIsUserSelected(false)
} else {
setIsUserSelected(true)
}
You can check whether user is selected or not without using hooks. All you need is one state hook.
const User = props => {
const [selectedUser, setSelectedUser] = useState(null);
const handleUserSelect = user => setSelectedUser(user.id === selectedUser.id ? null : user);
return (
<>
<Users onSelectUser={handleUserSelect} />
<Checkbox checked={Boolean(selectedUser)} />
</>
)
}
If selectedUser is null Boolean(selectedUser) will return false otherwise it will return true. You don't need extra hook for this.
You do not need to store the 'isUserSelect' information since it will be redundant with the 'selectUser === null' condition.
Here is a code proposal
export default function UserApp() {
const [ selectedUser, setSelectedUser ] = useState(null);
const handleUserClick = (user) => {
if(selectedUser === user) {
setSelectedUser(null)
} else {
setSelectedUser(user)
}
}
return (
<div className="App">
<Users onUserClick={handleUserClick} />
</div>
)
}
export default function Users({ onUserClick }) {
return (
<ul>
{USERS_DATA.map((user, index) => (
<li
key={index}
className="users"
onClick={() => onUserClick(user)}
>
{user.user_name}
</li>
))}
</ul>
)
}
note: code not tested, might contain some typos