Reputation: 57
I have a canvas and when i click on it, it draws a line.
Line is a function:
const line = (x1, y1, x2, y2) => {
return (
<line id="lineD" x1={x1} y1={y1} x2={x2} y2={y2} style={{ stroke: "black", strokeWidth: 3, strokeLinecap: "round" }}></line>
)
}
It works fine, except when I scale the canvas. When I do so, I change a scale
state.
So I want line attributes to be like this: x1={x1 * scale}
, but it only sets it once.
This is how I add lines, (content is another state):
content.push(line(100, 100, 200, 200))
(these are just random numbers)
And svg is: <svg>{content}</svg>
Upvotes: 0
Views: 92
Reputation: 4672
As mentioned in the comments it is not a good practice to store components in state.
This SO answer explains why.
Storing elements for later use directly breaks this core concept. You risk having stale elements that do not correspond to the current set of properties.
Instead you could store the data points of the lines.
const [content, setContent] = [
{
x1: 100,
y1: 100,
x2: 100,
y2: 100,
},
];
const [scale, setScale] = useState(1);
Your Line
component
const Line = ({ x1, y1, x2, y2, scale }) => {
return (
<line
id="lineD"
x1={x1 * scale}
y1={y1 * scale}
x2={x2 * scale}
y2={y2 * scale}
style={{ stroke: "black", strokeWidth: 3, strokeLinecap: "round" }}
></line>
);
};
When rendering the lines you can simply map
over the content
and add the props to the Line
component
<svg>
{content.map((lineData) => {
return <Line {...lineData} scale={scale} />;
})}
</svg>
Upvotes: 0
Reputation: 15996
React is "reacting" only to state or props update. Since your line
function returns JSX, you should turn it into a real React component and pass your data as props to make the rendering dynamic. Something like that:
const Line = (props) => {
const {x1, y1, x2, y2, scale} = props;
return (
<line id="lineD" x1={x1 * scale} y1={y1 * scale} x2={x2 * scale} y2={y2 * scale} style={{ stroke: "black", strokeWidth: 3, strokeLinecap: "round" }}></line>
);
}
Note the uppercase L in Line
: this is mandatory for React to see it as a component. Then you may use it to produce your array:
content.push(<Line x1={100} y2={100} x2={200} y2={200} scale={scale} />)
But a state should not be muted. You should use the set function you get from useState
:
const [content, setContent] = useState([]);
...
// do the following in an event handler, or in a useEffect
setContent([...content, <Line x1={100} y2={100} x2={200} y2={200} scale={scale} />]);
This will update the state and trigger a new rendering
Upvotes: 1