Closed jlei523 closed 4 years ago
Nestable is a controlled component. Do you update items
in your state?
Thanks for the reply.
I don't update items in my state. In fact, I don't even have items
in my state at all. It's an object outside of the React class.
Note that running this.setState for any state, even states that have nothing to do with Nestable, will cause Nestable to not apply drag changes.
onDragChange(items, item) {
this.setState({
anyState: "any change"
});
}
<Nestable
collapsed
items={items}
renderItem={renderItem}
handler={<span style={handlerStyles} />}
ref={ref}
onChange={(items, item) => this.onDragChange(items, item)}
/>
You have <Nestable items={items}
. How exactly do you store items
?
If you create it during every render, than updating the local state would create a new instance of items, which would be equal the initial shape of items.
Example: <Nestable items={items.slice(0)}
will restore the initial items
on every render of a parent component.
Try to check (on every render) if you accidentally update the link to your items
. Make sure you pass the same instance for every render. Or update it in onChange
.
You have
<Nestable items={items}
. How exactly do you storeitems
? If you create it during every render, than updating the local state would create a new instance of items, which would be equal the initial shape of items. Example:<Nestable items={items.slice(0)}
will restore the initialitems
on every render of a parent component.
Right now I'm just storing it in an object outside of the class. I have a function to convert that object into an object that works with Nestable.
import Nextable from "./nestable.jsx";
import { convertCostCentersIntoItems } from "./util";
let costCentersTest = {
"1": "HEAD OFFICE",
"2": "UK",
"3": "INTERNATIONAL",
"2-4": "UK > MANCHESTER",
"2-5": "UK > LONDON",
"2-5-7": "UK > LONDON > VAN-1",
"2-5-7-9": "UK > LONDON > VAN-1 > DRIVER-1",
"2-5-8": "UK > LONDON > VAN-2",
"2-5-8-10": "UK > LONDON > VAN-2 > DRIVER-2",
"2-6": "UK > BIRMINGHAM"
};
class CostCenters extends Component {
constructor(props) {
super(props);
this.state = {
needsSave: false,
newCostCenterName: "",
userChangedItems: []
};
this.onDragChange = this.onDragChange.bind(this);
}
async componentDidMount() {
const response = await fetch(baseUrl + "/api/cost_centres_get");
const data = await response.json();
console.log(data);
this.setState({
items: convertCostCentersIntoItems(data)
});
}
collapse = collapseCase => {
if (this.refNestable) {
switch (collapseCase) {
case 0:
this.refNestable.collapse("NONE");
break;
case 1:
this.refNestable.collapse("ALL");
break;
case 2:
this.refNestable.collapse([1]);
break;
}
}
};
onDragChange(items, item) {}
updateInputValue = event => {
this.setState({
newCostCenterName: event.target.value.toUpperCase()
});
};
submitNewCostCenter = () => {
let obj = {
id: 10,
text: this.state.newCostCenterName
};
this.setState({
items: this.state.items.concat(obj)
});
};
render() {
return (
<div>
<Controls
updateInputValue={this.updateInputValue}
submit={this.submitNewCostCenter}
cancel={this.hideNewCostCenterInput}
collapse={this.collapse}
/>
<Nextable
items={convertCostCentersIntoItems(costCentersTest)}
ref={el => (this.refNestable = el)}
onChange={this.onDragChange}
/>
</div>
);
}
}
import React from "react";
import Nestable from "react-nestable";
import EdiText from "react-editext";
const handlerStyles = {
position: "absolute",
top: 0,
left: 0,
width: "12px",
height: "100%",
background: "steelblue",
cursor: "pointer"
};
const styles = {
position: "relative",
padding: "10px 15px",
fontSize: "20px",
border: "1px solid #f9fafa",
background: "#f9fafa",
cursor: "pointer",
display: "flex"
};
const renderItem = ({ item, collapseIcon, handler }) => {
return (
<div style={styles}>
{handler}
{collapseIcon}
<EdiText showButtonsOnHover value={item.text} onSave={() => {}} />
</div>
);
};
export default ({ items, ref, onChange }) => {
return (
<div>
<Nestable
collapsed
items={items}
renderItem={renderItem}
handler={<span style={handlerStyles} />}
ref={ref}
onChange={(items, item) => onChange(items, item)}
/>
</div>
);
};
convertCostCentersIntoItems(costCentersTest)
creates you a new instance of the Array every time component gets rerendered, which resets the internal state of Nestable.
convertCostCentersIntoItems(costCentersTest)
creates you a new instance of the Array every time component gets rerendered, which resets the internal state of Nestable.
What's a way to fix this? Thanks!
Try to use memo pattern.
convertCostCentersIntoItems
should (as an example) make a "shallow equal" check and return a new instance only when data was actually changed.
Try to use memo pattern.
convertCostCentersIntoItems
should (as an example) make a "shallow equal" check and return a new instance only when data was actually changed.
If I use one of the example objects that doesn't need any formatting, it's still the same issue. IE. If I clone the example in the repo, add a this.setState to the onChange function, it'll still have the same issue.
Is there a pattern that you recommend without having to resort to using memo?
Check this part: https://github.com/primetwig/react-nestable/blob/master/src/Nestable/Nestable.js#L85 You have at least these 2 to be always new on every render:
handler={<span style={handlerStyles} />}
onChange={(items, item) => onChange(items, item)}
handler
can be saved into top level variable.
onChange
can be passed as is.
Check this part: https://github.com/primetwig/react-nestable/blob/master/src/Nestable/Nestable.js#L85 You have at least these 2 to be always new on every render:
handler={<span style={handlerStyles} />} onChange={(items, item) => onChange(items, item)}
handler
can be saved into top level variable.onChange
can be passed as is.
Ahh! The issue seemed to be handler. If I remove handler, it worked without changing anything else.
<Nestable
collapsed
items={items}
renderItem={renderItem}
ref={ref}
onChange={onChange}
/>
handler
can be saved into top level variable. Can you show me what you mean by this?
This caused the same rerender issue.
const Handler = () => {
return <span style={handlerStyles} />;
};
<Nestable
collapsed
items={items}
renderItem={renderItem}
handler={<Handler />}
ref={ref}
onChange={onChange}
/>
const handler = <span style={handlerStyles} />;
<Nestable handler={handler} />
const handler = <span style={handlerStyles} />; <Nestable handler={handler} />
Worked! Thank you for your help!
Whenever this.setState is in the onChange function, drag and drop does nothing. The items do not move.
Any ideas?