Hi i am new to react and stuck with react-beautiful-dnd issue.
I Seem to have configured as per the documentation but still facing this weird issue related to draggable id.
made draggableid as string
provided index as number
assigned innerref properly
But still the issue persist.
Need some expert help in this area.
CodeSandBox Link : Link to react beautiful dnd codesandbox issue code
Also adding the code for quick glance:
import "./styles.css";
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
import { useState } from "react";
export default function App() {
const [list, setList] = useState(generateData());
const st = {
width: "300px",
cursor: "grab",
display: "flex",
gap: "10px",
flexDirection: "column"
};
const onDragEnd = (result) => {
if (result.destination) {
alert("drag successfull");
}
};
return (
<div className="App">
<h4>Test</h4>
<div>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={st}
className="work-parent"
>
<WorkList list={list} />
</div>
)}
</Droppable>
</DragDropContext>
</div>
</div>
);
}
function WorkList({ list }) {
return list.map((l, index) => <Work key={l.id} work={l} index={index} />);
}
function Work({ work, index }) {
const st = {
padding: "10px",
width: "100%",
color: "white",
backgroundColor: "purple",
width: "200px",
height: "50px"
};
return (
<Draggable draggableId={work.id} key={work.id} index={index}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={st}
>
{work.title}
</div>
)}
</Draggable>
);
}
function generateData() {
const data = [];
for (let i = 0; i < 10; i++) {
data.push({
title: "Work - " + i,
id: makeid(5)
});
}
return data;
}
function makeid(length) {
var result = "";
var characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
For the first look your code is correct. The problem that you faced is about upgrading a React v18. As a temporary solution I can advise you to remove <StrictMode> wrapper and your app will work.
You can find more information about this issue here: https://github.com/atlassian/react-beautiful-dnd/issues/2350
UPDATE:
Downgrade to React v17 also might help:
https://github.com/atlassian/react-beautiful-dnd/issues/2407
UPDATE 2:
I have not tested it by myself but seems that this could be a workaround to use React v18 and do not remove <StrictMode>:https://github.com/atlassian/react-beautiful-dnd/issues/2399#issuecomment-1167427762
Related
I passed a function to the child to check a checkbox and then to set setDispatch(true), the problem is that when I check the checkbox everything freezes and the website stops until I close and open again.
the function:
const [selectedChkBx, setSelectedChkBx] = useState({ arrayOfOrders: [] });
const onCheckboxBtnClick = (selected) => {
const index = selectedChkBx.arrayOfOrders.indexOf(selected);
if (index < 0) {
selectedChkBx.arrayOfOrders.push(selected);
} else {
selectedChkBx.arrayOfOrders.splice(index, 1);
}
setSelectedChkBx(selectedChkBx)
toggleDispatchButton()
};
const toggleDispatchButton = () => {
if (selectedChkBx.arrayOfOrders.length == 0) {
setDispatchButtonDisplay(false)
}
else {
setDispatchButtonDisplay(true)
}
}
Child Component:
<form style={{ display: 'block' }} >
<Row sm={1} md={2} lg={3}>
{ordersDisplay.map((value, key) => {
return (
<motion.div key={value.id} layout>
<DeliveryQueueComp
selectedChkBx={selectedChkBx}
toggleDispatchButton={toggleDispatchButton}
setDispatchButtonDisplay={setDispatchButtonDisplay}
value={value}
onCheckboxBtnClick={onCheckboxBtnClick}
/>
</motion.div>
)
})
}
</Row> </form>
DeliveryQueueComp Code:
<div
className={styles1.checkBox}
style={{ background: selectedChkBx.arrayOfOrders.includes(value.id) ?
'#f84e5f' : 'transparent' }}
onClick={() => { onCheckboxBtnClick(value.id) }}
>
<FontAwesomeIcon icon={faCheck} style={{ fontSize: '10px', opacity:
selectedChkBx.arrayOfOrders.includes(value.id) ? '1' : '0' }} />
</div>
If I remove toggleDispatchButtonDisplay, it works but then after a while the page freezes again.
Any thoughts about this?
As you didn't provide setDispatch code I don't know what it does, but for the rest I think I know why it's not working.
You're assigning the array and then set it to the state. If you want to do this that way you should only do a forceUpdate instead of a setState (as it has already been mutated by push and splice).
To properly update your state array you can do it like this
const onCheckboxBtnClick = (selected) => {
const index = selectedChkBx.arrayOfOrders.indexOf(selected);
if (index < 0) {
//the spread in array creates a new array thus not editing the state
setSelectedChkBx({
arrayOfOrders: [...selectedChkBx.arrayOfOrders, selected]
});
} else {
// same thing for the filter here
setSelectedChkBx({
arrayOfOrders: selectedChkBx.arrayOfOrders.filter(
(value) => value !== selected
)
});
}
toggleDispatchButton();
};
Here is the sandbox of your code https://codesandbox.io/s/eager-kalam-ntc7n7
I'm trying to change the grid size on my Conway game of life app but when I click button to set new numCols/numRows only one of them is effected on the app. How do I affectively set new state so grid changes size as expected.
I have 2 buttons in the app, one to make grid smaller, one to make it bigger.
onClick they Trigger function sizeHandler & sizeHandler2.
My guess is I need to set new state in a different method but I tried a few methods to no avail.
import React, { useState } from 'react'
import './App.css';
function App() {
const color = "#111"
const [numRows, setNumRows] = useState(20)
const [numCols, setNumCols] = useState(20)
const generateEmptyGrid = () => {
const rows = [];
for (let i = 0; i < numRows; i++) {
rows.push(Array.from(Array(numCols), () => 0))
}
return rows
}
const [grid, setGrid] = useState(() => {
return generateEmptyGrid();
})
const sizeHandler = () => {
setNumRows(40)
setNumCols(40)
}
const sizeHandler2 = () => {
setNumRows(20)
setNumCols(20)
}
// RENDER
return (
<div className="page">
<div className="title">
<h1>
Conway's Game Of Life
</h1>
<button onClick={sizeHandler}>
Size+
</button>
<button onClick={sizeHandler2}>
Size-
</button>
</div>
<div className="grid" style={{
display: 'grid',
gridTemplateColumns: `repeat(${numCols}, 20px)`
}}>
{grid.map((rows, i) =>
rows.map((col, j) =>
<div className="node"
key={`${i}-${j}`}
style={{
width: 20,
height: 20,
border: 'solid 1px grey',
backgroundColor: grid[i][j] ? color : undefined
}}
/>
))}
</div>
</div>
);
}
export default App;
What you are doing is you want a change of numRows and numCols to have a side effect. You actually almost said it yourself. React has a hook for that: useEffect:
useEffect(() => {
setGrid(generateEmptyGrid())
}, [numRows, numCols]);
I read a couple of answers and all of them seems to assume you have a single object containing CSS instead of single properties, I tried the answers and I couldn't make it work, I was wondering what's wrong and what's the best way to do this, here is what I have done so far :
import React from 'react';
import FormLabel from '#material-ui/core/FormLabel';
const label = (props) => {
// <label onClick={props.onClick} className={props.className + ' ' + props.gridClass} style={props.inlineStyle} >{props.label}</label>
let divStyleArray = [];
if (typeof props.inlineStyle.background !== 'undefined') {
divStyleArray.push(props.inlineStyle.background)
delete props.inlineStyle.background
}
if (typeof props.inlineStyle.textAlign !== 'undefined') {
divStyleArray.push(props.inlineStyle.textAlign)
delete props.inlineStyle.textAlign
}
const customStyle = {
width: '100%'
}
const divStyle = Object.assign({}, ...divStyleArray);
return (
<div className={props.gridClass} style={{divStyle}}>
<FormLabel component="label" onClick={props.onClick} style={{ ...customStyle, ...props.inlineStyle }}>{props.label}</FormLabel>
</div>
)
}
export default label;
My goal is to extract a couple of CSS property, give it to the div and then give the rest to whats inside the div
Update 01:
I tried the answered given but it doesn't seem to work properly, here is what i did:
import React from 'react';
import FormLabel from '#material-ui/core/FormLabel';
const label = (props) => {
let inlineStyle = {
...props.inlineStyle
}
const divStyle = {
background: inlineStyle.background,
textAlign: inlineStyle.textAlign,
}
delete inlineStyle.background;
delete inlineStyle.textAlign;
const customStyle = {
width: '100%'
}
return (
<div className={props.gridClass} style={divStyle}>
<FormLabel component="label" onClick={props.onClick} style={{ ...customStyle, ...inlineStyle }}>{props.label}</FormLabel>
</div>
)
}
export default label;
First of all deleting stuff from the props object would be anti-pattern, or at least bad practice as far as I know.
If you only need the two properties you use there you could use this code:
const label = (props) => {
let divStyle = {
background: props.background,
textAlign: props.textAlign,
};
const customStyle = {
width: '100%'
}
return (
<div className={props.gridClass} style={{divStyle}}>
<FormLabel
component="label"
onClick={props.onClick}
style={{
...customStyle,
...props.inlineStyle,
background: undefined,
textAlign: undefined,
}}
>{props.label}</FormLabel>
</div>
)
}
Im attempting to build a website using Material-UI and React. When attempting to use Material-UI's styling via the Hook API, it works online in codesandbox.io but does not work locally when I run it. The border radius property does not seem to update, nor do any of the properties in the button or instruction object
import React from 'react';
import { makeStyles } from '#material-ui/styles';
import Stepper from '#material-ui/core/Stepper';
import Step from '#material-ui/core/Step';
import StepLabel from '#material-ui/core/StepLabel';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
const useStyles = makeStyles({
root: {
width: "100%"
},
button: {
marginRight: 10,
borderRadius: 100,
fontSize: 20,
},
instructions: {
marginTop: 2,
marginBottom: 5
}
});
function getSteps() {
return ['Select campaign settings', 'Create an ad group', 'Create an ad'];
}
function getStepContent(step) {
switch (step) {
case 0:
return 'Select campaign settings...';
case 1:
return 'What is an ad group anyways?';
case 2:
return 'This is the bit I really care about!';
default:
return 'Unknown step';
}
}
function HorizontalLinearStepper() {
const classes = useStyles();
const [activeStep, setActiveStep] = React.useState(0);
const [skipped, setSkipped] = React.useState(new Set());
const steps = getSteps();
function isStepOptional(step) {
return step === 1;
}
function isStepSkipped(step) {
return skipped.has(step);
}
function handleNext() {
let newSkipped = skipped;
if (isStepSkipped(activeStep)) {
newSkipped = new Set(newSkipped.values());
newSkipped.delete(activeStep);
}
setActiveStep(prevActiveStep => prevActiveStep + 1);
setSkipped(newSkipped);
}
function handleBack() {
setActiveStep(prevActiveStep => prevActiveStep - 1);
}
function handleSkip() {
if (!isStepOptional(activeStep)) {
// You probably want to guard against something like this,
// it should never occur unless someone's actively trying to break something.
throw new Error("You can't skip a step that isn't optional.");
}
setActiveStep(prevActiveStep => prevActiveStep + 1);
setSkipped(prevSkipped => {
const newSkipped = new Set(prevSkipped.values());
newSkipped.add(activeStep);
return newSkipped;
});
}
function handleReset() {
setActiveStep(0);
}
return (
<div className={classes.root}>
<Stepper activeStep={activeStep}>
{steps.map((label, index) => {
const stepProps = {};
const labelProps = {};
if (isStepOptional(index)) {
labelProps.optional = <Typography variant="caption">Optional</Typography>;
}
if (isStepSkipped(index)) {
stepProps.completed = false;
}
return (
<Step key={label} {...stepProps}>
<StepLabel {...labelProps}>{label}</StepLabel>
</Step>
);
})}
</Stepper>
<div>
{activeStep === steps.length ? (
<div>
<Typography className={classes.instructions}>
All steps completed - you're finished
</Typography>
<Button onClick={handleReset} className={classes.button}>
Reset
</Button>
</div>
) : (
<div>
<Typography className={classes.instructions}>{getStepContent(activeStep)}</Typography>
<div>
<Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
Back
</Button>
{isStepOptional(activeStep) && (
<Button
variant="contained"
color="primary"
onClick={handleSkip}
className={classes.button}
>
Skip
</Button>
)}
<Button
variant="contained"
color="primary"
onClick={handleNext}
className={classes.button}
>
{activeStep === steps.length - 1 ? 'Finish' : 'Next'}
</Button>
</div>
</div>
)}
</div>
</div>
);
}
export default HorizontalLinearStepper;
You can view the expected results here: https://98m6j7m314.codesandbox.io
in which the buttons border is circular after applying the borderRadius property
When using #material-ui/styles with #material-ui/core you need to follow the installation step https://v3.material-ui.com/css-in-js/basics/#migration-for-material-ui-core-users.
Here's your codesandbox link working: https://codesandbox.io/s/material-demo-rv2w1
Web browsers use cache and in some cases your changes are not reloaded. Refershing using Ctrl+f5, clearing or disabling cache in your settings may be useful.
Please attempt to see your localhost web page using another web browser & in incognito
I need to make this logic to be executed every time when input field value is changed:
let warningMessage = ''
if (stateData) {
let list = []
if (props.values.injured_worker_type === 'Seasonal') {
list = stateData.calculation_warnings['Seasonal']
} else {
list = stateData.calculation_warnings[`FullTime-${props.values.working_days}`]
}
const keys = _.keys(list)
const index = _.findIndex(keys, key => {
const fromValue = Number(key.slice(1, key.indexOf('-')))
const toValue = Number(key.slice(key.indexOf('-') + 1, key.length))
return props.values.total_days_paid >= fromValue && props.values.total_days_paid < toValue
})
if (index >= 0) {
warningMessage = list[keys[index]]
}
}
const message = warningMessage ? (
<p style={{ color: 'red', fontSize: '0.85rem' }}> {warningMessage} </p>
) : null
And pass downthis messeage to be outputed as result of this logic:
const message = warningMessage ? (
<p style={{ color: 'red', fontSize: '0.85rem' }}> {warningMessage} </p>
) : null
Here is JSX(html) part when I have that input field:
return (
<Fragment>
<Form.Group grouped style={{ marginTop: '2rem' }}>
<label style={{ fontSize: '0.85rem' }}>8. Total days in preceeding 52 weeks:</label>
<Form.Input
name="total_days_paid"
onChange={this.handleChange}
width="6"
placeholder="200"
required
/>
</Form.Group>
{/* THIS messeage is result of that logic which I need to
be executed every time on changed input */}
{message}
</Fragment>
)
}
Here is not working version of code in stackblitz:
https://stackblitz.com/edit/react-tpk1ik
How I can make this to works?
You code is not up to the mark. You are doing many mistakes in your code.
I have corrected all your code and here is the working solution of handler function https://react-t3luq3.stackblitz.io.
index.js
import React from 'react'
import ReactDom from "react-dom";
import Hello from './Hello';
ReactDom.render(<Hello />, document.getElementById("root"));
Hello.js
import React, { Component, Fragment } from 'react'
import { Form } from 'semantic-ui-react'
import _ from 'lodash'
export default class Hello extends Component{
constructor(props){
super(props);
}
handleChange = e => {
console.log(e.target.value)
}
render(){
const { stateData } = this.props;
let warningMessage = ''
if (stateData) {
let list = []
if (props.values.injured_worker_type === 'Seasonal') {
list = stateData.calculation_warnings['Seasonal']
} else {
list = stateData.calculation_warnings[`FullTime-${props.values.working_days}`]
}
const keys = _.keys(list)
const index = _.findIndex(keys, key => {
const fromValue = Number(key.slice(1, key.indexOf('-')))
const toValue = Number(key.slice(key.indexOf('-') + 1, key.length))
return props.values.total_days_paid >= fromValue && props.values.total_days_paid < toValue
})
if (index >= 0) {
warningMessage = list[keys[index]]
}
}
const message = warningMessage ? (
<p style={{ color: 'red', fontSize: '0.85rem' }}> {warningMessage} </p>
) : null
return (
<Fragment>
<Form.Group grouped style={{ marginTop: '2rem' }}>
<label style={{ fontSize: '0.85rem' }}>8. Total days in preceeding 52 weeks:</label>
<Form.Input
name="total_days_paid"
onChange={this.handleChange}
width="6"
placeholder="200"
required
/>
</Form.Group>
{message}
</Fragment>
)
}
}
index.html
<html>
<body>
<div id="root"></div>
</body>
</html>
The code in your example doesn't help much because it has errors and even when I install the missing dependencies it outputs nothing, but just from reading it I can see an issue.
The logic you want to execute when the input value changes needs to go inside the handleChange method you are trying to call here onChange={this.handleChange}.
For reference, these type of input fields are called Controled Components and you can read more about them in the React Documentation.