Nuka-carousel react move to certain slide - javascript

I've got a question about npm package 'nuka-carousel. How to perform goToSlide on clicked element. I have list of elements with scroll3d setting. If I click on e.g last visible element I would like to scroll carousel so that element would be in a center.

According to their GitHub documentation, you can take control of the carousel just by adding onClick to your control button and then use setState() to change the slideIndex:
import React from 'react';
import Carousel from 'nuka-carousel';
export default class extends React.Component {
state = {
slideIndex: 0
};
render() {
return (
<Carousel
slideIndex={this.state.slideIndex}
afterSlide={slideIndex => this.setState({ slideIndex })}
>
...
</Carousel>
<button onClick={(event) => this.handlesClick(event, index)}> />
);
}
handleClick = (event, index) => {
event.preventDefault();
this.setState({slideIndex: index});
}
}

Related

Want to render different component after click on Add Button

I want to render VehicleInfoRender.js when click on 'Add' button which is in UMUIMAdditionalCoverage.js
App.js
import './App.css';
const App = () => {
return (
<BasicLayout />
);
}
export default App;
First add a state to manage toggling VehicleInfoRender
state = { activeIndex: 0, showVehicleInfo: false}
Then add a function to toggle showing and hiding the component
<Button onClick={this.toggleVehicleInfo}>Add</Button>
const toggleVehicleInfo = () => {
this.setState((prevState) => {showVehicleInfo: !prevState.showVehicleInfo});
};
Finally add this where you want to render the component
{this.state.showVehicleInfo && <VehicleInfoRender />}
Use state (eg: isShowVehicleInfoRender) to handle turn on/off render this component

How to access the state of a component at a superior level without using useContext?

let me explain my question.
I would like to create expanding flex cards, here is the exemple on codepen : https://codepen.io/z-/pen/OBPJKK
and here is my code for each button :
basically I have a component which is called HomeButtons that generates every flex cards. Inside this component I have a smaller component called readMore. In this component I have a useState that allows me to toggle individually each button to add or retreive an active class. If the active class is present, that means that the selected button must expand and the other ones must shrink.
What I would like to do is to access the readMore state ouside of the readMore subcomponent. That way I could write a function to remove the active class from a card if the user clicks on another card like so :
function setToUnactive() {
if (readMore(true)) {
readMore(false)}
}
My question is how can I get the state of readMore outside of the readMore subcomponent ? Do I need to use useContext ? Because that seems very simple to do but I tried a lot of things and nothing works. Can I pass the state readMore as a prop of the component ReadMore ? Thank you !
import React, { useState } from 'react';
import '../style/catalogue.scss';
import collectionsItems from '../Components/collectionsItemsData';
import { Link } from "react-router-dom";
const HomeButtons = ({}) => {
function ReadMore() {
const [readMore, setReadMore] = useState(false)
function toggleSetReadMore() {
setReadMore(!readMore)
}
return (
<p className='showmore' onClick={toggleSetReadMore} className={readMore ? "collection-item active" : "collection-item"}>TOGGLE BUTTON</p>
)
}
return <div>
{collectionsItems.map((collectionItem) => {
const { id, category, img } = collectionItem;
return < article key={id} >
<img className="item-img" src={img} alt=''/>
<ReadMore />
<Link to={`/${category}`} className="item-title">{category}</Link>
</article>
})}
</div>
}
export default HomeButtons;
First of all you need extract ReadMore component from function outside!
And for your problem you can lift state up(https://reactjs.org/docs/lifting-state-up.html). And since at the same time only one item can be opened you can do something like this:
function ReadMore({ isOpened, setOpened }) {
return (
<p
onClick={setOpened}
className={isOpened ? "collection-item active" : "collection-item"}
>
TOGGLE BUTTON
</p>
);
}
const HomeButtons = () => {
const [openedItemId, setOpenedItemId] = useState(null);
return (
<div>
{collectionsItems.map((collectionItem) => {
const { id, category, img } = collectionItem;
return (
<article key={id}>
<img className="item-img" src={img} alt="" />
<ReadMore
isOpened={openedItemId === id}
setOpened={() => setOpenedItemId(id)}
/>
<Link to={`/${category}`} className="item-title">
{category}
</Link>
</article>
);
})}
</div>
);
};

onBlur / onClick conflict with CodeMirror2 in React

I have created multiple CodeMirror cells. OnBlur works fine, however if I click run button on the other cell, instead of firing run, it actually triggers onBlur and then I need to click mouse again to trigger run. Ideally both of these events should be fired when run button is clicked.
I have seen that the issue is with the order of precedence for these two events and one of the proposed solutions was to add ref attribute to code mirror like this ref = {cell => this.cell = cell} and then in the other handler which is related to run button do this.cell.focus() or in some similar way.
Unfortunately I am not even able to access ref attribute for CodeMirror2 so I can't test it. I will paste both of these components and any suggestion is appreciated.
To summarize: The issue is that onBlur shadows onClick, so run button needs to be clicked twice. I want to be able to click run button and that both onBlur and handleRunClick fire.
import React, { Component } from "react";
import { Controlled as CodeMirror } from "react-codemirror2";
import CellResults from "./CellResults";
import CellToolbar from "../Shared/CellToolbar";
import AddCellButton from "../Shared/AddCellButton";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/darcula.css";
import "codemirror/mode/javascript/javascript.js";
import "codemirror/mode/ruby/ruby.js";
import "codemirror/mode/python/python.js";
class CodeCell extends Component {
state = {
code: this.props.cell.code
};
handleChange = value => {
this.setState({ code: value });
};
handleBlur = () => {
this.props.onUpdateCodeState(this.state.code, this.props.cellIndex);
if (this.props.language === "Markdown") {
this.props.toggleRender(this.props.cellIndex);
}
};
render() {
const cell = this.props.cell;
const cellOptions = {
mode: cell.type.toLowerCase(),
theme: "darcula",
lineNumbers: true,
showCursorWhenSelecting: true
};
return (
<div>
<div className="add-cell-container">
<AddCellButton
className="add-cell-btn"
onClick={this.props.onAddClick}
cellIndex={this.props.cellIndex}
/>
</div>
<CellToolbar
cellIndex={this.props.cellIndex}
onDeleteClick={this.props.onDeleteClick}
language={cell.type}
onLanguageChange={this.props.onLanguageChange}
rendered={cell.rendered}
onRunClick={this.props.onRunClick}
/>
<CodeMirror
value={this.state.code}
options={cellOptions}
onBeforeChange={(editor, data, value) => {
this.handleChange(value);
}}
onBlur={this.handleBlur}
/>
{cell.type !== "Markdown" ? (
<CellResults language={cell.type} results={cell.results} />
) : null}
</div>
);
}
}
export default CodeCell;
import React from "react";
import Button from "react-bootstrap/Button";
class RunCellButton extends React.Component {
handleRunClick = () => {
this.props.onClick(this.props.cellIndex);
};
render () {
return (
<Button
className="run-button"
onClick={this.handleRunClick}
variant="secondary"
size="sm"
>
<span>►</span>
</Button>
);
}
};
export default RunCellButton;
Below is the similar problem with Adding Cell. When I trigger click event it fires, the state of show is changed to true but if I log it on line 36 it is still false. I am triggering click event from a different component, again due to this obBlue shadowing everything else so every button needs to be clicked twice.
import React, { Component } from "react";
import SplitButton from "react-bootstrap/SplitButton";
import * as constants from "../../Constants/constants";
import DropdownButton from "react-bootstrap/DropdownButton";
import Dropdown from "react-bootstrap/Dropdown";
class AddCellButton extends Component {
state = {
show: false
}
handleSelectCellType = language => {
this.props.onClick(this.props.cellIndex, language);
};
handleToggle = () => {
this.setState((prevState) => {
return {
show: !prevState["show"]
}
})
}
render() {
const dropDownItems = constants.LANGUAGES.map(language => {
return (
<Dropdown.Item
as="button"
value={language}
key={language}
eventKey={language}
>
{language}
</Dropdown.Item>
);
});
console.log("state of show " + this.state.show)
return (
<DropdownButton
show={this.state.show}
onToggle={this.handleToggle}
className="add-cell-btn"
variant="secondary"
id="dropdown-basic-button"
title={<span>+</span>}
size="sm"
onSelect={this.handleSelectCellType}
>
{dropDownItems}
</DropdownButton>
);
}
}
export default AddCellButton;

State Change Causing Sidebar Reload

I am building an online store. When you click the checkout button, a sidebar slides into view showing the list of items in your cart. Inside of the cart is its list of items. You can change the quantity by toggling the up/down arrows in a Form.Control element provided by Bootstrap-React.
The way my code works is that when you toggle the up/down arrows to add or decrease the product quantity the state changes in the parent regarding what's in your cart. This triggers the child cart sidebar to close then reopen. I do not want this to happen! The sidebar should remain open.
I've tried two things; one is to use event.preventDefault() to try and make it so the page isn't refreshed, but this hasn't worked.
The other thing is trying to use shouldComponentUpdate and checking for whether the item quantity was changed, then preventing the app from re-rendering. This is the code I was using:
shouldComponentUpdate(nextProps, nextState) {
if (
nextState.cart &&
nextState.cart.length > 0 &&
this.state.cart.length > 0
) {
console.log("Next state cart num= " + nextState.cart[0].num)
console.log("curr state cart num= " + this.state.cart[0].num)
if (nextState.cart[0].num != this.state.cart[0].num) {
return false;
}
}
return true;
}
The problem is that my previous and future props are the same! Hence I can't write any code preventing re-rendering on item quantity change.
Can anyone provide some advice?
If your component is re rendering but its props and state aren't changing at all then you could prevent this with either React memo if you're using a function or if you're using a class based component then extending React.PureComponent instead of React.Component.
Both ways will do a shallow prop and state comparison and decide whether it should re render or not based on the result of said comparison. If your next props and state are the same as before then a re render will not be triggered.
Here's a codepen example so you can decide which one to use.
class App extends React.Component {
state = {
count: 0
};
handleClick = event => {
event.preventDefault();
this.setState(prevState => ({ count: prevState.count + 1 }));
};
render() {
return (
<div>
<span>Click counter (triggers re render): {this.state.count}</span>
<button style={{ marginLeft: "10px" }} onClick={this.handleClick}>
Click me to re render!
</button>
<SingleRenderClassComponent />
<SingleRenderFunctionComponent />
<AlwaysReRenderedClassComponent />
<AlwaysReRenderedFunctionComponent />
</div>
);
}
}
class SingleRenderClassComponent extends React.PureComponent {
render() {
console.log("Rendered React.PureComponent");
return <div>I'm a pure component!</div>;
}
}
const SingleRenderFunctionComponent = React.memo(
function SingleRenderFunctionComponent() {
console.log("Rendered React.memo");
return <div>I'm a memoized function!</div>;
}
);
class AlwaysReRenderedClassComponent extends React.Component {
render() {
console.log("Rendered React.Component");
return <div>I'm a class!</div>;
}
}
function AlwaysReRenderedFunctionComponent() {
console.log("Rendered function component");
return <div>I'm a function!</div>;
}
ReactDOM.render(<App />, document.getElementById("root"));

How to simulate mouse over event on a div using enzyme for testing a react application?

I have a div that onMouseOver and onMouseLeave toggles a child div as a dropdown. I want to test the hover event using enzyme.
The relevant code for the component is:
<div className="search-category" onMouseOver={() => toggleDropdown(true)} onMouseLeave={() => toggleDropdown(false)}>
<div className="search-type">
...
</div>
{dropdownShown && <SearchMenu searchSections={searchSections} dispatch={dispatch} />}
</div>
The relevant test code is
...
it('should toggle search type dropdown on mouse hover', () => {
expect(enzymeWrapper.find('.SearchMenu').exists()).toEqual(false);
enzymeWrapper.find('.search-category').simulate('mouseOver');
expect(enzymeWrapper.find('.SearchMenu').exists()).toEqual(true);
});
...
.SearchMenu is the className of the SearchMenu component.
toggleDropdown is a simple function that toggles the dropdownShown flag.
The issue i'm facing is that even after calling .simulate, the expect on the last line returns false when it should return true. The code is working perfectly as I can see the dropdown on the browser and in the element tab of the browser.
Please let me know if any more details are required.
Any help would be highly appreciated.
If I have replicated your issue correctly, here is the working demo, of the test cases you were trying to run. I have written a number of test cases using enzyme and jest, and I think this is the right way to do the testing. :)
Toggle.js
import React from "react";
export const SearchMenu = () => <input />;
class Toggle extends React.Component {
state = { dropdownShown: true };
toggleDropdown = value => {
this.setState({ dropdownShown: value });
};
render() {
return (
<div
className="search-type"
onMouseOver={() => this.toggleDropdown(true)}
onMouseLeave={() => this.toggleDropdown(false)}
>
<h1>Hover over me to hide/unhide the input</h1>
{this.state.dropdownShown && <SearchMenu />}
</div>
);
}
}
export default Toggle;
Toggle.spec.js
import React from "react";
import { shallow } from "enzyme";
import Toggle from "./Toggle";
import Enzyme from "enzyme";
import { SearchMenu } from "./Toggle";
describe("Toggle Component", () => {
it("check state", () => {
const wrapper = shallow(<Toggle />);
expect(wrapper.find(<SearchMenu />).exists).toBeTruthy();
// Testing Initial State
expect(wrapper.state("dropdownShown")).toBe(true);
wrapper.simulate("mouseleave");
// Testing state after mouseleave
expect(wrapper.state("dropdownShown")).toBe(false);
// Testing state after mouseover
wrapper.simulate("mouseover");
expect(wrapper.state("dropdownShown")).toBe(true);
});
});
Chasing Unicorn's answer above is almost perfect. Instead of passing mouseover to wrapper.simulate, it should be mouseenter.
This worked for me:
it('sets hoveredOver state to true/fase from mouseenter and mouseleave events', () => {
const wrapper = shallow(<MyComponent {...defaultProps} />);
// initial state:
expect(wrapper.state('hoveredOver')).toBe(false);
wrapper.simulate('mouseenter');
expect(wrapper.state('hoveredOver')).toBe(true);
wrapper.simulate('mouseleave');
expect(wrapper.state('hoveredOver')).toBe(false);
});
This is with Enzyme v3.3.0 in my package.json

Categories

Resources