How would this React code look without React-hooks and with class components rather than functional components? - reactjs

I just studied React from YouTube lessons, and there all the lessons were built on classes and the usual this.setState, without hooks. How would this React code look without React-hooks and with class components rather than functional components?
The code itself implements an image slider:
React:
function Slider({ items }) {
const [ active, setActive ] = React.useState(0);
const { length, [active]: slide } = items;
const next = e => setActive((active + +e.target.dataset.step + length) % length);
const goTo = e => setActive(+e.target.dataset.index);
React.useEffect(() => {
const timeout = setTimeout(() => setActive((active + 1 + length) % length), 5000);
return () => clearTimeout(timeout);
}, [active, length]);
return (
<div>
<div className="slideshow-container">
<div className="mySlides fade">
<div className="numbertext">{active + 1} / {length}</div>
<img src={slide.img} />
<div className="text">{slide.title}</div>
</div>
<a className="prev" onClick={next} data-step={-1}>❮</a>
<a className="next" onClick={next} data-step={+1}>❯</a>
</div>
<div className="dots">
{items.map((n, i) => (
<span
key={n.id}
className={`dot ${i === active ? 'active' : ''}`}
onClick={goTo}
data-index={i}
></span>
))}
</div>
</div>
);
}
const items = [
{ title: 'One', img: 'https://upload.wikimedia.org/wikipedia/commons/1/1f/Purity_of_nature.jpg' },
{ title: 'Two', img: 'https://mairie-balma.fr/wp-content/uploads/2016/06/Lhers.jpg' },
{ title: 'Three', img: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRt-b1iBqHQ_emkm1wFmkM7KQskzIqg7YQPZWW85Sa7k2nNLwgjMw' },
].map((n, i) => ({ ...n, id: i + 1 }));
ReactDOM.render(<Slider items={items} />, document.getElementById('app'));
HTML
<div id="app"></div>
CSS:
.slideshow-container {
max-width: 500px;
position: relative;
margin: auto;
}
.prev, .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -22px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
.prev:hover, .next:hover {
background-color: rgba(0,0,0,0.8);
}
.text {
color: #f2f2f2;
font-size: 15px;
padding: 8px 12px;
position: absolute;
bottom: 8px;
width: 100%;
text-align: center;
box-sizing: border-box;
}
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
.dots {
display: flex;
justify-content: center;
}
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active, .dot:hover {
background-color: #717171;
}
.mySlides img {
width: 100%;
}

Something like this (not fully tested):
class Slider {
constructor(props) {
super(props);
this.state = {
active: 0
}
}
let timeout = null;
componentDidMount() {
this.timeout = setTimeout(() => this.setActive(), 5000);
}
componentDidUpdate(prevProps) {
const { active } = this.props;
if (prevProps.active !=== active {
if (this.timeout) {
clearTimeout(this.timeout);
}
this.timeout = setTimeout(() => this.setActive(), 5000);
});
}
componentDidUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
const setActive = (newActive) => {
const { length } = items;
this.setState({
active: (newActive + 1 + length) % length
});
}
const next = e => {
const { length } = items;
this.setActive((this.state.active + +e.target.dataset.step + length) % length);
}
const goTo = e => this.setActive(+e.target.dataset.index);
render() {
const { length } = items;
const {active} = this.state;
return (
<div>
<div className="slideshow-container">
<div className="mySlides fade">
<div className="numbertext">{active + 1} / {length}</div>
<img src={slide.img} />
<div className="text">{slide.title}</div>
</div>
<a className="prev" onClick={this.next} data-step={-1}>❮</a>
<a className="next" onClick={this.next} data-step={+1}>❯</a>
</div>
<div className="dots">
{items.map((n, i) => (
<span
key={n.id}
className={`dot ${i === active ? 'active' : ''}`}
onClick={this.goTo}
data-index={i}
></span>
))}
</div>
</div>
);
}
}
const items = [
{ title: 'One', img: 'https://upload.wikimedia.org/wikipedia/commons/1/1f/Purity_of_nature.jpg' },
{ title: 'Two', img: 'https://mairie-balma.fr/wp-content/uploads/2016/06/Lhers.jpg' },
{ title: 'Three', img: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRt-b1iBqHQ_emkm1wFmkM7KQskzIqg7YQPZWW85Sa7k2nNLwgjMw' },
].map((n, i) => ({ ...n, id: i + 1 }));
ReactDOM.render(<Slider items={items} />, document.getElementById('app'));

Related

How to import Formik?

port './App.css';
function App() {
return (
<>
<div className='container'>
</div>
</>
);
}
ooooooo iiiiiii lk;jv
import React from 'react'
import { Field, Form, Formik} from 'formik';
function Add() {
return (
<Formik
initialValues={{ email: '', firstName: '', lastName: '', myPassword: '' }}
onSubmit={(values) => {
console.log(values)
}}
>
<Form>
<Field type="email" name="email" placeholder="Email" />
<Field name="lastName" placeholder="Doe" />
<Field name="myPassword" placeholder="Password" type="password" />
<button type="submit">Submit</button>
</Form>
</Formik>
)
}
export default Add
https://codesandbox.io/s/elastic-hill-cmbz1?from-embed=&file=/src/Carousel.css:0-429
// App.js //
import Carousel, { CarouselItem } from "./Carousel"; import gtr1
from './assets/gtr.jpg'
export default function App() { return (
<div className="image">
<img src={gtr1}></img>
<div className="txt">
<h1> HeyyyyY!</h1>
</div>
</div>
</CarouselItem>
</Carousel>
</div> ); }
// Carousel.js //
import React, { useEffect, useState } from "react"; import {
useSwipeable } from "react-swipeable";
import "./Carousel.css";
export const CarouselItem = ({ children, width }) => { return (
<div className="carousel-item" style={{ width: width }}>
{children}
); };
const Carousel = ({ children }) => { const [activeIndex,
setActiveIndex] = useState(0); const [paused, setPaused] =
useState(false);
const updateIndex = (newIndex) => {
if (newIndex < 0) {
newIndex = React.Children.count(children) - 1;
} else if (newIndex >= React.Children.count(children)) {
newIndex = 0;
}
setActiveIndex(newIndex); };
useEffect(() => {
const interval = setInterval(() => {
if (!paused) {
updateIndex(activeIndex + 1);
}
}, 3000);
return () => {
if (interval) {
clearInterval(interval);
}
}; });
const handlers = useSwipeable({
onSwipedLeft: () => updateIndex(activeIndex + 1),
onSwipedRight: () => updateIndex(activeIndex - 1) });
return (
<div
{...handlers}
className="carousel"
onMouseEnter={() => setPaused(true)}
onMouseLeave={() => setPaused(false)}
>
<div
className="inner"
style={{ transform: translateX(-${activeIndex * 100}%) }}
>
{React.Children.map(children, (child, index) => {
return React.cloneElement(child, { width: "100%" });
})}
<button
onClick={() => {
updateIndex(activeIndex - 1);
}}
>
Prev
{React.Children.map(children, (child, index) => {
return (
<button
className={${index === activeIndex ? "active" : ""}}
onClick={() => {
updateIndex(index);
}}
>
{index + 1}
);
})}
<button
onClick={() => {
updateIndex(activeIndex + 1);
}}
>
Next
); };
export default Carousel;
// Carousel.css //
*{ margin: 0; } .carousel {
overflow: hidden; }
.inner {
white-space: nowrap;
transition: transform 1s; }
.carousel-item {
display: inline-flex;
align-items: center;
justify-content: center;
color: #fff; }
.indicators {
display: flex;
justify-content: center; }
.indicators > button {
margin: 5px; }
.indicators > button.active {
background-color: green;
color: #fff; }
.image img{
width: 100%;
height: 700px;
position: relative;
display: flex;
align-items: center;
text-align: center;
justify-content: center; } .image{
position: relative;
display: flex;
} .txt{
position: absolute;
display: flex;
justify-content: center;
text-align: center;
width: 100%;
height: 700px;
align-items: center;
} .txt h1{
font-size: 30px;
color: aqua;
margin-bottom: 200px; }

How do I dynamically add a div where mouse was clicked in React?

I'm new to react and wonder how to do weird code stuff. I have a div component that I need to add child divs to depending on where I clicked on the div. I could do this easily in vanilla JS - here is a code sandbox of JS of what I want to do : https://codepen.io/Webasics/pen/YXXyEO
here is what I have in react so far (this is inside my App component):
const imgAdder = (e) => {
console.log(e.pageX, e.pageY)
}
<main onClick={imgAdder} </main>
$(document).ready(function() {
$(this).click(function(e) {
var x = e.pageX;
var y = e.pageY;
$('<div/>').css({
'top': y,
'left': x
}).appendTo('body');
});
});
div {
background-color: red;
width: 50px;
height: 50px;
position: absolute;
transform: translate(-50%, -50%);
/* optional */
border: 1px solid black;
/* optional */
}
h2 {
z-index: 10;
/* optional */
/* This always keeps the title on top*/
position: absolute;
}
body {
background-color: #E1E7E8;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h2>Click anywhere</h2>
Any directions would be lovely ! thank you.
function App() {
// declare array of boxes
const [boxes, setBoxes] = useState([]);
const handleClick = ({ pageX, pageY }) => {
// on every click push a new coordinate to the boxes array
setBoxes((boxes) => [...boxes, { x: pageX, y: pageY }]);
};
return (
<div className="app" onClick={handleClick}>
// display boxes
{boxes.map((box) => (
// map coordinates to left and top
<div className="box" style={{ left: box.x, top: box.y }}></div>
))}
</div>
);
}
Styles, mostly copied from the codepen
.app {
width: 100%;
height: 100vh;
}
.box {
position: absolute;
width: 50px;
height: 50px;
background: red;
transform: translate(-50%, -50%);
}
sandbox
Weird, but I like it!
https://codesandbox.io/s/elated-meadow-zuerrg?file=/src/App.js
I would simply use useEffect to register a click handler on the document and on click, add elements to a state array.
Finally, render those elements onto the page.
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const elements = useDynamicElements();
return (
<>
<h2>Click anywhere</h2>
{elements}
</>
);
}
const useDynamicElements = () => {
const [state, setState] = useState([]);
useEffect(() => {
const handler = (event) => {
setState((previous) => [
...previous,
<div style={{ top: event.pageY, left: event.pageX }} />
]);
};
document.addEventListener("click", handler);
return () => document.removeEventListener("click", handler);
});
return state;
};
An over simplified example in React could be like this:
This version can run in the snippets below for convenience.
const App = () => {
const [boxList, setBoxList] = React.useState([]);
const handleClick = (e) => {
if (e.target.classList.contains("btn")) {
setBoxList([]);
return;
}
setBoxList((prev) => {
const { pageX, pageY } = e;
const newBox = { left: pageX, top: pageY };
return [...prev, newBox];
});
};
return (
<div className="app" onClick={handleClick}>
<button className="btn">CLEAN UP</button>
<h2>Click anywhere</h2>
{boxList.length > 0 &&
boxList.map((box, index) => (
<div className="box" style={{ top: box.top, left: box.left }} key={index}></div>
))}
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.app {
width: 100%;
height: 100vh;
background-color: pink;
position: relative;
}
.box {
background-color: #000;
width: 50px;
height: 50px;
position: absolute;
transform: translate(-50%, -50%);
border: 1px solid black;
}
h2 {
top: 50%;
left: 50%;
position: absolute;
transform: translate(-50%, -50%);
}
.btn {
margin: 15px;
padding: 15px;
background-color: #fff;
border: 0;
border-radius: 12px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

Input checkbox didn't work what I expected

I tried to make an input checkbox when I click the input checkbox, it should be displayed a check image like this.
However, it didn't show the checkbox and I am not sure how to check that the input box was checked or not. Could you help me with what part do I missed and where is something wrong?
I really appreciate your help!
This is CSS inputl and label part
.colors {
display: flex;
flex-direction: column;
span {
margin-bottom: 20px;
}
.colorLists {
margin-left: 10px;
display: flex;
flex-wrap: wrap;
.colorLayout {
display: flex;
flex-direction: column;
position: relative;
width: 33%;
height: 80px;
flex-shrink: 0;
align-items: center;
justify-content: center;
.checkboxLabel {
background-color: beige;
border: 1px solid #ccc;
border-radius: 50%;
cursor: pointer;
height: 28px;
left: 0;
position: absolute;
top: 40;
width: 28px;
&:after {
border: 2px solid #fff;
border-top: none;
border-right: none;
content: '';
height: 6px;
left: 7px;
opacity: 0;
position: absolute;
top: 8px;
transform: rotate(-45deg);
width: 12px;
// opacity: 0.2;
}
}
input[type='checkbox'] {
visibility: hidden;
}
input[type='checkbox']:checked {
& + label {
background-color: beige;
border-color: beige;
&:after {
opacity: 1;
}
}
}
.productColor {
margin-top: 70px;
font-size: 13px;
margin-right: 21px;
}
}
}
}
.sizes {
.HorizontalLine {
margin-top: 25px;
}
.span {
}
.sizeLists {
margin-top: 20px;
margin-bottom: 20px;
button {
margin: 5px;
width: 44px;
height: 32px;
background-color: white;
border: 1px solid silver;
border-radius: 15%;
}
}
}
This is js part
<div className="colors">
<span>색상</span>
<ul className="colorLists">
{COLOR_LISTS.map((color, idx) => {
return (
<li className="colorLayout" key={idx}>
<input type="checkbox" />
<label
className="checkboxLabel"
for="checkbox"
style={{ backgroundColor: color.colorProps }}
/>
<span className="productColor">{color.color_name}</span>
</li>
);
})}
</ul>
</div>
In react you have to set the htmlFor property for the label instead of for.
The value should be the same as the id from the input.
Then you can add a value property for the input which is used for adding/removing the item in the list of selected items.
For this purpose a handleChange function can be defined.
const [selectedItems, setSelectedItems] = useState([]);
function handleChange(e) {
let newSelected = [];
if (selectedItems.includes(e.target.value)) {
newSelected = selectedItems.filter((item) => item !== e.target.value);
} else {
newSelected = [...selectedItems, e.target.value];
}
setSelectedItems(newSelected);
}
return (
<div className="colors">
<span>색상</span>
<ul className="colorLists">
{COLOR_LISTS.map((color, idx) => {
return (
<li className="colorLayout" key={idx}>
<input
onChange={handleChange}
type="checkbox"
id={idx}
value={color.color_name}
checked={selectedItems.includes(color.color_name)}
/>
<label
className="checkboxLabel"
htmlFor={idx}
style={{ backgroundColor: color.colorProps }}
/>
<span className="productColor">{color.color_name}</span>
</li>
);
})}
</ul>
</div>
);
EDIT: Since you are using a class component it can be rewrittenlike this:
export default class CheckboxListComponent extends Component {
constructor(props) {
super(props);
this.state = { selectedItems: [] };
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
let newSelected = [];
if (this.state.selectedItems.includes(e.target.value)) {
newSelected = this.state.selectedItems.filter(
(item) => item !== e.target.value
);
} else {
newSelected = [...this.state.selectedItems, e.target.value];
}
this.setState({ selectedItems: newSelected });
}
render() {
return (
<div className="colors">
<span>색상</span>
<ul className="colorLists">
{COLOR_LISTS.map((color, idx) => {
return (
<li className="colorLayout" key={idx}>
<input
onChange={this.handleChange}
type="checkbox"
id={idx}
value={color.color_name}
checked={this.state.selectedItems.includes(color.color_name)}
/>
<label
className="checkboxLabel"
htmlFor={idx}
style={{ backgroundColor: color.colorProps }}
/>
<span className="productColor">{color.color_name}</span>
</li>
);
})}
</ul>
</div>
);
}
}
You must tell react that your input is checked so that your CSS will apply it. selected ids must be kept in a place for future existence check. in the following code, I named this array selecetedIdx.
You also need to add idx on selection(via onChange event handler) or wrap them all in form and add them via extra dom attribute.
class Main extends Component {
// initialize selectedIdx with [] in your state (esp constructor)
// e.g. this.state = {/* rest of state, */ selectedIdx: []}
render() {
return (
{COLOR_LISTS.map((color, idx) => {
return (
// ...
<input
type="checkbox"
checked={selectedIdx.includes(idx)}
onChange={() => this.setState(state => ({
selectedIdx: [...state.selectedIdx, idx]
}))}
/>
// ...
)}
)
}
Your checkbox element needs name and value properties and would normally be a child of the <form> element.

React how to repopulate values when back button clicked

In react js i get value from api then i used component to populated vale after back button clicked i don`t want to remove my value i want to my current data that work in text filed but it not work on
select it always remove it value.it show error name not defined.
i want repopulate select when clicked back button
import React from 'react';
import styled from 'styled-components';
import Select from 'react-select';
import { useNavigate } from 'react-router-dom';
import { QsrQoreApi, Eats365, StoreHub } from './Sources';
import SourceStoreSelection from './SourceStoreSelection';
import svgs from '../../shared/svgs';
import { Modal, withAuth } from '../../shared';
const StyledSourceSettings = styled.div`
& .header {
display: flex;
height: 5.2rem;
align-items: center;
border-bottom: 0.1rem solid #edf2f7;
}
& .back {
height: 2rem;
width: 2rem;
margin-left: 2rem;
}
& .title {
margin-left: max(1.5rem, calc(((100vw - 21rem) / 2) - 4rem));
width: 21rem;
height: 2rem;
font-size: 1.6rem;
font-weight: 700;
line-height: 2rem;
text-align: center;
color: #2d3748;
}
& .source-form {
padding: 2rem;
display: grid;
grid-template-columns: 1fr;
}
& .login {
width: 28rem;
margin: 0 auto 0.4rem auto;
font-size: 1.6rem;
font-weight: 700;
color: #2d3748;
}
& .form-input {
margin: 1.5rem auto 0 auto;
width: 28rem;
font-size: 1.6rem;
color: #4a5568;
}
& .form-input > .input {
width: 28rem;
margin: 0.5rem 0 0 0;
height: 3.6rem;
font-size: 1.6rem;
border: 0.1rem solid #a0aec0;
border-radius: 0.4rem;
color: #4a5568;
padding: 1rem;
}
& .form-input > .select {
margin: 0.5rem 0 0 0;
}
& .buffer-152px {
height: 15.2rem;
}
& .buffer-91px {
height: 9.1rem;
}
& .selected-store {
width: 28rem;
height: 2rem;
margin: 2rem auto 0 auto;
font-size: 1.6rem;
font-weight: 700;
color: #2d3748;
}
& .selected-store-detail {
display: flex;
height: 5.1rem;
margin: 0 auto;
align-items: center;
border-bottom: 0.1rem solid #edf2f7;
font-size: 1.6rem;
color: #4a5568;
}
& .selected-store-detail > .map {
height: 2rem;
width: 2rem;
}
& .selected-store-detail > .name {
height: 2rem;
width: 22rem;
margin-left: 1rem;
}
& .selected-store-detail > .forward {
height: 2rem;
width: 2rem;
margin-left: 1rem;
}
& .next-btn {
width: 28rem;
height: 3.6rem;
margin: auto;
margin-top: max(5.3rem, calc(100vh - 47.1rem));
border: 0.1rem solid #cbd5e0;
border-radius: 0.4rem;
background: #ffffff;
box-shadow: 0rem 0.2rem 0.4rem rgba(24, 39, 75, 0.12);
padding: 1rem;
font-size: 1.6rem;
font-weight: 600;
color: #4a5568;
}
& .next-btn:disabled,
& .next-btn[disabled] {
box-shadow: none;
color: #cbd5e0;
}
`;
const sourceOpts = [
{ value: 'QsrQoreApi', label: 'QsrQoreApi' },
{ value: 'Eats365', label: 'Eats365' },
{ value: 'StoreHub', label: 'StoreHub' },
];
const sourceSelectStyles = {
control: (provided) => ({
...provided,
width: '28rem',
minHeight: '3.6rem',
height: '3.6rem',
fontSize: '1.6rem',
border: '0.1rem solid #a0aec0',
borderRadius: '0.4rem',
color: '#4a5568',
}),
indicatorSeparator: () => {},
singleValue: (provided) => ({
...provided,
color: '#4a5568',
}),
valueContainer: (provided) => ({
...provided,
padding: '0.2rem 0.8rem',
}),
placeholder: (provided) => ({
...provided,
margin: 'auto 0.2rem',
}),
input: (provided) => ({
...provided,
margin: '0.2rem',
padding: '0.2rem auto',
}),
dropdownIndicator: (provided) => ({
...provided,
'& svg': {
height: '2rem',
width: '2rem',
},
}),
indicatorsContainer: (provided) => ({
...provided,
'& > div': {
padding: '0.8rem',
},
}),
menu: (provided) => ({
...provided,
borderRadius: '0.4rem',
margin: '0.8rem auto',
}),
menuList: (provided) => ({
...provided,
maxHeight: '30rem',
padding: '0.4rem 0',
}),
option: (provided) => ({
...provided,
padding: '0.8rem 1.2rem',
}),
};
function AddSource(props) {
const { setForm, store, setStore , source} = props;
const [sourceAdditionalInfos, setSourceAdditionalInfos] = React.useState({});
const [sourceStore, setSourceStore] = React.useState(null);
const [showModal, setShowModal] = React.useState(false);
const navigate = useNavigate();
React.useEffect(() => {
if(store.source){
const infos = store.source.additionalInfos.reduce((result, { key, value }) => {
const temp = result;
temp[key] = value;
return temp;
}, {});
setSourceAdditionalInfos(infos);
}
},[]);
React.useEffect(() => {
if (store.source) {
const infospos = store.source.type
const value = infospos;
setSourceStore(value);
}
},[]);
const onBackClick = () => {
navigate(-1);
};
const onSourceSelectChange = (source) => {
if (source) {
setStore({ ...store, source: { type: source.value } });
setSourceStore(null);
}
};
const handleChange = (e) => setSourceAdditionalInfos({ ...sourceAdditionalInfos, [e.target.id]: e.target.value });
const onSubmit = (e) => {
e.preventDefault();
if (!sourceStore) setShowModal(true);
else {
const addInfos = Object.entries(sourceAdditionalInfos).map(([k, v]) => ({ key: k, value: v }));
let st = {
...store,
source: {
...store.source,
...sourceStore.value,
additionalInfos: addInfos.concat(sourceStore.value.additionalInfos),
},
};
setStore(st);
setForm('addStore');
}
};
let renderSource = <div className="buffer-152px" />;
if (store.source) {
switch (store.source.type) {
case 'QsrQoreApi':
renderSource = (
<QsrQoreApi
handleChange={handleChange}
sourceAdditionalInfos={sourceAdditionalInfos}
disableInput={sourceStore}
/>
);
break;
case 'Eats365':
renderSource = (
<Eats365
handleChange={handleChange}
sourceAdditionalInfos={sourceAdditionalInfos}
disableInput={sourceStore}
/>
);
break;
case 'StoreHub':
renderSource = (
<StoreHub
handleChange={handleChange}
sourceAdditionalInfos={sourceAdditionalInfos}
disableInput={sourceStore}
/>
);
break;
default:
renderSource = <div className="buffer-152px" />;
break;
}
}
let renderSelectedSourceStore = '';
if (sourceStore) {
renderSelectedSourceStore = (
<>
<div className="selected-store">Store selection</div>
<div className="selected-store-detail" onClick={() => setShowModal(true)}>
<img src={svgs.map} className="map" alt="map" />
<div className="name">{sourceStore.value.name}</div>
<img src={svgs.forward} className="forward" alt="forward" />
</div>
</>
);
} else {
renderSelectedSourceStore = <div className="buffer-91px" />;
}
return (
<StyledSourceSettings>
<div className="header">
<img src={svgs.back} className="back" alt="back" onClick={onBackClick} />
<div className="title">POS System</div>
</div>
<form className="source-form" onSubmit={onSubmit}>
<div className="login">Login credentials</div>
<label className="form-input" htmlFor="type">
<div className="label">POS System</div>
<div className="select">
<Select
options={sourceOpts}
styles={sourceSelectStyles}
placeholder="Choose one"
onChange={onSourceSelectChange}
inputId="type"
isDisabled={sourceStore}
/>
</div>
</label>
{renderSource}
{renderSelectedSourceStore}
<input className="next-btn" type="submit" value="NEXT" disabled={!(store.source && store.source.type)} />
</form>
<Modal onClose={() => setShowModal(false)} open={showModal}>
<SourceStoreSelection
onSubmitted={() => setShowModal(false)}
onClosed={() => setShowModal(false)}
store={store}
sourceAdditionalInfos={sourceAdditionalInfos}
sourceStore={sourceStore}
setSourceStore={setSourceStore}
/>
</Modal>
</StyledSourceSettings>
);
}
export default withAuth(AddSource);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
enter image description here
Try to change it to:
{sourceStore?.value?.name}

How to open a multiple message box with ReactJS

I'm building a multiple chatbox messaging like Facebook's popup messenger windows. At the moment, the user can call up a chatbox, close it, minimize it, etc.
When I click on multiple users, say 3, I'm supposed to have three chatboxes pop up corresponding to those three different users. Currently, only one chatbox appears.
This screenshot illustrates what I want to achieve. On each user's button click, it's own chatbox will popup.
Here is the demo and download link for a jQuery equivalent: link.
This is the full React code which shows just one chat box:
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
import axios from 'axios';
import './style.css';
class MessageBox extends Component {
constructor() {
super();
this.state = {
showBox: false,
shownToggle: true,
data: [
{ id: "1", name: "Tony" },
{ id: "2", name: "Mark" },
{ id: "3", name: "Joy" }
],
currentRec: undefined,
};
this.showBox = this.showBox.bind(this);
this.closeBox = this.closeBox.bind(this);
this.toggle = this.toggle.bind(this);
}
showBox = (i, pid, name) => {
this.setState({ currentRec: i });
console.log(`Selected record index: ${i}`);
alert(pid);
alert(name);
this.setState({ showBox: true }, () => {
document.addEventListener('click', this.closeBox);
});
}
closeBox(event) {
if (this.dropdownBox.contains(event.target)) {
this.setState({ showBox: false }, () => {
document.removeEventListener('click', this.closeBox);
});
}
}
toggle() {
this.setState({
shownToggle: !this.state.shownToggle
});
}
render() {
var hidden = {
display: this.state.shownToggle ? "block" : "none"
}
return (
<div>
<ul style={{ float: "right" }}>
{this.state.data.map((person, i) => (
<div className="chat-sidebar" key={i}>
<button onClick={() => this.showBox(i, person.id, person.name)}>Chat with {person.name}</button>
{this.state.showBox ? (
<div className="msg_box" style={{ right: '270px' }}>
<div onClick={this.toggle.bind(this)} class="msg_head">
(<b style={{ color: 'orange' }}>
{this.state.currentRec !== undefined &&
<div className="modal-body">
{this.state.data[this.state.currentRec].name}
({this.state.data[this.state.currentRec].id})
</div>
}
</b>)
Minimize
<div className="close" ref={(element) => { this.dropdownBox = element; }} style={{ color: 'white' }}>Close</div>
</div>
<div style={hidden} className="msg_wrap"><div className="msg_body">Message will appear here</div></div>
</div>) : (null)}
</div>
))}
</ul>
</div>
);
}
}
/****** Chat Popup Layout ******/
body{
background: #e5e5e5;
font-family: sans-serif;
}
.msg_box{
position: fixed;
bottom: -5px;
width: 250px;
background: white;
border-radius: 5px 5px 0px 0px;
}
.msg_head{
background: black;
color: white;
padding: 8px;
font-weight: bold;
cursor: pointer;
border-radius: 5px 5px 0px 0px;
}
.msg_body{
background: white;
height: 200px;
font-size: 12px;
padding: 15px;
overflow: auto;
overflow-x: hidden;
}
.close{
float: right;
cursor: pointer;
}
.minimize{
float: right;
cursor: pointer;
padding-right: 5px;
}
/****** Slider Layout Popup ******/
.chat-sidebar {
width: 250px;
height: 100%;
right: 0px;
top: 0px;
padding-top: 10px;
padding-bottom: 10px;
border: 1px solid #b2b2b2;
}
After series of efforts, the use of jquery and Reactjs is what solved my issue as per code below
const dataSet = this.state.data;
alert(dataSet);
if ($.inArray(pid, dataSet) != -1)
{
dataSet.splice($.inArray(pid, this.state.data), 1);
}
dataSet.unshift(pid);
var s = 270 ; // start position
var j = 260; //next position
$.each(dataSet, function( index, value ) {
if(index < 4){
$('[rel="'+value+'"]').css("right",s);
$('[rel="'+value+'"]').show();
s = s+j;
}
else{
$('[rel="'+value+'"]').hide();
}

Resources