Is it possible to target a className in a useState hook? target.className == "test" is what I am looking at specifically. Is it possible to look for a class and if that class is active hide/show another div page element?
I may be way off with this but, looking for suggestions.
// Click tracking of className "test"
const [isSelected, setIsSelected] = useState(true)
const selectToggle = (target.className == "test") =>
setIsSelected({ ...isSelected, [test]: !isSelected[test] })
You can track element with its reference using useRef, check the console which will log the element it tracks:
import React, { useState, useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
const App = () => {
const [isSelected, setIsSelected] = useState(true);
const elementRef = useRef();
useEffect(() => {
console.log(elementRef.current);
});
const toggle = () => setIsSelected(s => !s);
return (
<>
{isSelected && <div ref={elementRef}>Im Tracked</div>}
<button onClick={toggle}>{`Click to ${
isSelected ? 'disable' : 'enable'
}`}</button>
</>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
Related
self is not defined error when i use jodti-react in nextjs project
import React, { useState, useRef, useMemo } from "react";
import Dashborad from "./Dashborad";
import JoditEditor from "jodit-react";
import dynamic from "next/dynamic";
export default function edit() {
const editor = useRef();
const [content, setContent] = useState("");
return (
<Dashborad>
<JoditEditor
ref={editor}
value={content}
tabIndex={1} // tabIndex of textarea
onBlur={(newContent) => setContent(newContent)} // preferred to use only this option to update the content for performance reasons
onChange={(newContent) => setContent(newContent)}
/>
</Dashborad>
);
}
}
how to solve this error ?
create jodit.js file
import { useRef, useMemo } from 'react'
import JoditEditor from 'jodit-react'
const Jodit = ({ content, setContent }) => {
const editor = useRef(null)
return (
<JoditEditor
ref={editor}
value={content}
tabIndex={1} // tabIndex of textarea
onBlur={(newContent) => setContent(newContent)} // preferred to use only this option to update the content for performance reasons
onChange={(newContent) => setContent(newContent)}
/>
)
}
export default Jodit
Use dynamic import
const Jodit = dynamic(() => import('./Jodit'), { ssr: false })
I'm supposed to have a modal appear with an image in it. There are next and previous buttons which controls which image you are currently viewing. The modal is rendered in a portal. That in itself is working correctly. However, when I add children, and those childrens are updated, the modal only (not the portal) gets removed from the flow. In the React DevTools, the "isOpen" state of the modal is still set to true. I am using React 17.0.2 with NextJS 12.0.4 and Styled Components 5.3.3.
I have tried:
memoizing my components (as you can see there are some remnants of those trials) but this did not work
extracting the state of the modal to the parent and passing it as props and it didn't work either
I know there must be something wrong that I'm doing here so if you could help me find it that would be much appreciated!
Here is the controller where the modal is rendered:
import { FC, MouseEventHandler, useEffect, useState } from "react";
import { Photo } from "services/Images/Images.interfaces";
import { useGetNextPhoto, useGetPhotos, useGetPreviousPhoto } from "state";
import SlideshowContextProvider from "./Context/SlideshowContext";
import SlideShowModal from "./SlideShowModal";
const SlideshowController: FC = () => {
const photos = useGetPhotos();
const [currentlyViewedPhoto, setCurrentlyViewedPhoto] = useState<Photo | null>(null);
const nextPhoto = useGetNextPhoto(currentlyViewedPhoto?.id);
const previousPhoto = useGetPreviousPhoto(currentlyViewedPhoto?.id);
const onPreviousRequest: MouseEventHandler<HTMLButtonElement> = (event) => {
event.preventDefault();
setCurrentlyViewedPhoto(previousPhoto);
};
const onNextRequest: MouseEventHandler<HTMLButtonElement> = async (event) => {
event.preventDefault();
setCurrentlyViewedPhoto(nextPhoto);
};
useEffect(() => {
setCurrentlyViewedPhoto(photos[0]);
}, [photos]);
return (
<SlideshowContextProvider
currentlyViewing={currentlyViewedPhoto}
onNextSlideRequest={onNextRequest}
onPreviousSlideRequest={onPreviousRequest}
>
<SlideShowModal />
</SlideshowContextProvider>
);
};
export default SlideshowController;
The SlideshowModal:
import { Modal } from "components";
import { FC } from "react";
import SlideshowControlBar from "./SlideshowControlBar";
import SlideshowImage from "./SlideshowImage";
const SlideShowModal: FC = () => {
return (
<Modal uniqueKey="slideshow">
<SlideshowImage />
<SlideshowControlBar />
</Modal>
);
};
export default SlideShowModal;
The modal in itself:
import Portal from "components/Portal/Portal";
import { FC, useEffect, useMemo, useState } from "react";
import { useRegisterModal } from "state";
import styled from "styled-components";
import useWindowScrollLock from "./hook/UseWindowScrollLock";
interface Props {
uniqueKey: string;
isBackgroundOpaque?: boolean;
}
... Styled elements
const Modal: FC<Props> = ({ uniqueKey, isBackgroundOpaque = true, children }) => {
const [isOpen, setIsOpen] = useState(false);
const open = () => setIsOpen(true);
const close = () => setIsOpen(false);
const register = useRegisterModal(uniqueKey);
const isModalOpen = useMemo(() => isOpen, [isOpen]);
useEffect(() => {
register({ open, close });
}, [register]);
useWindowScrollLock(isModalOpen);
return isModalOpen ? (
<Portal>
<Container>
<InnerModal>
<Close onClick={close}>X</Close>
{children}
</InnerModal>
</Container>
<Background onClick={close} opaque={isBackgroundOpaque} />
</Portal>
) : null;
};
export default Modal;
I am trying to test a react component using Enzyme. I am not able to test the click on the IconButton component and the function doesn't get called when i simulate a click.
This is how IconButton is defined on an external component.
var IconButton = function (props) {
return (React.createElement(IconButton$1, { color: 'default', onClick: props.onClick, disabled: props.disabled, size: props.size, onMouseDown: props.onMouseDown }, props.children));
};export{Button,IconButton};
This is how I am using it in my app.
import React, {useState, useEffect} from 'react';
import { Drawer } from '#material-ui/core';
import ExpandLessIcon from '#material-ui/icons/ExpandLess';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import { IconButton } from '#mycomponent/button';
export default function Component1 {
const classes = useStyles();
const [open, setOpen] = useState(true);
const handleClick = function (event) {
if (event) {
setOpen(!open);
}
else {
return;
}
};
return (
<Drawer>
<div className="classname1">
<IconButton onClick={(e) => handleClick(e)} className={classes.button, "iconBtn"}>
{open ? <ExpandLessIcon data-test="lessIcon" /> : <ExpandMoreIcon data-test="moreIcon" />}
</IconButton>
</div>
</Drawer>
);
}
Here is my test for simulating the click on the Icon Button. I also tried another way to check that the handleClick was getting called but it still fails.
const wrapper = shallow(<Component1 />);
it('Test the button click', () => {
expect(wrapper.containsMatchingElement(<ExpandMoreIcon />)).toBeTruthy()
const element = wrapper.find(".iconBtn")
const mockEvent = {target: {}};
element.simulate('click', mockEvent)
expect(wrapper.containsMatchingElement(<ExpandLessIcon />)).toBeTruthy()
})
Try changing this line:
const element = wrapper.find("button").at(0);
or you could find it by it's className from debug():
const element = wrapper.find(".MuiButtonBase-root MuiIconButton-root");
Notice that you'd simulate a click on an actual html button in such case.
I have tried some solutions that came by, on this link particularily...
I tried changing value inside my TodosContext.js file.. which didn't work, too..
One more thing that I have tried is to call useContext() function from another component, that didn't work neither..
Here's my code.
App.js:
import React, { useState, useContext } from 'react';
import TodoList from './components/TodoList';
import NewTodo from './components/NewTodo';
import { TodosProvider, TodosContext } from './components/contextapi/TodosContext';
function App() {
const [input, setInput] = useState('');
const [todos, setTodos] = useContext(TodosContext);
const _handleInput = (e) => {
setInput(e.target.value)
}
const _todoAdd = (e) => {
if (e.key === 'Enter') {
setTodos(
[...todos, { content: input, id: Date.now(), completed: false }]
)
setInput('')
}
}
const _todoRemove = (id) => {
const newTodos = todos.filter(todo => todo.id !== id)
setTodos(newTodos)
}
return (
<div>
<header>
<h3>To-Do Manager | Context API</h3>
</header>
<TodosProvider>
<NewTodo newTodo={_todoAdd} handleInput={_handleInput} newVal={input} />
<TodoList todos={todos} />
</TodosProvider>
</div>
);
}
export default App;
TodosContext.js:
import React, { useState, createContext } from 'react';
export const TodosContext = createContext()
export const TodosProvider = ({ children }) => {
const [todos, setTodos] = useState([]);
return (
<TodosContext.Provider value={[todos, setTodos]}>{children}</TodosContext.Provider>
)
}
TodoList.js:
import React, { useContext } from 'react';
import Todo from './Todo';
import RemoveTodoFromList from './RemoveTodoFromList';
import { TodosContext } from './contextapi/TodosContext'
function TodoList() {
const [todos, setTodos] = useContext(TodosContext);
return (
<div>
{todos.map(todo => (
<div>
<Todo key={todo.id} todo={todo} />
</div>
))}
</div>
)
}
export default TodoList
I'm really struggling with this one, I spent whole day figuring out what went wrong.. Thanks!
We fixed it inside the comments.
createContext needs an object as parameter that defines your context.
In your case it should be export const TodosContext = createContext([[],() => {}]).
So the application knows the first element of the tuple is an array and so iterable.
For the life of me I can't figure out why the Spin Now won't hide upon clicking it. It rightfully shows Claim Now upon clicking Spin Now but once Claim Now shows, I want the Spin Now to hide. I'm using hooks, what am I doing wrong?
import React, { useState } from 'react';
import SpinNowButton from '../../components/SpinNowButton/SpinNowButton';
import ClaimNowButton from '../../components/ClaimNowButton/ClaimNowButton';
import './Buttons.css';
const Buttons = () => {
const [showSpin, setShowSpin] = useState(false);
const [showClaim, setShowClaim] = useState(false);
return(
<div className="both-buttons">
<SpinNowButton onClick={() => setShowClaim(true)}/>
{showClaim ? <ClaimNowButton/> : null}
{showSpin ? <SpinNowButton/> : null}
</div>
);
};
export default Buttons;
So you only need one piece of state to accomplish this, and you set it to the opposite of what the value was previously. Then the ternary components below will render one component if true, and the other if false.
Edit - I think this is closer to what you're looking for:
import React, { useState } from 'react';
import SpinNowButton from '../../components/SpinNowButton/SpinNowButton';
import ClaimNowButton from '../../components/ClaimNowButton/ClaimNowButton';
import './Buttons.css';
const Buttons = () => {
const [showClaim, setShowClaim] = useState(false);
const handleCLick = () => {setShowClaim(!showClaim)}
return(
<div className="both-buttons">
{showClaim ? null : <SpinNowButton onClick{() => handleClick()}/>}
{showClaim ? <ClaimNowButton onClick{() => handleClick()}/> : null}
</div>
);
};
export default Buttons;
An implementation which is flexible in adding more types such as claim/spin:
import React, { useState } from 'react';
import SpinNowButton from '../../components/SpinNowButton/SpinNowButton';
import ClaimNowButton from '../../components/ClaimNowButton/ClaimNowButton';
import './Buttons.css';
const Buttons = () => {
const [shownItems, setShownItems] = useState(['spin']);
return(
<div className="both-buttons">
{shownItems.contains('claim') && <ClaimNowButton onClick={() => setShownItems('spin')}/>}
{shownItems.contains('spin') && <SpinNowButton onClick={() => setShownItems('claim')}/>}
</div>
);
};
export default Buttons;