typescript.react.best-practice.react-props-in-state.react-props-in-state
semgrep
Author
4,056
Download Count*
License
Copying a prop into state in React -- this is bad practice as all updates to it are ignored. Instead, read props directly in your component and avoid copying props into state.
Run Locally
Run in CI
Defintion
rules:
- id: react-props-in-state
pattern-either:
- patterns:
- pattern-inside: |
class $CN extends React.Component {
...
}
- pattern-either:
- pattern: |
state = {$NAME: <... this.props.$PROP ...>}
- pattern: |
this.state = {$NAME: <... this.props.$PROP ...>}
- metavariable-regex:
metavariable: $NAME
regex: ^(?!default|initial).*$
- patterns:
- pattern-either:
- pattern-inside: |
function $FN({$PROP},...) {
...
}
- pattern-inside: |
function $FN($PROP,...) {
...
}
- pattern-either:
- pattern: useState(<... $PROP ...>)
- pattern: useState(<... $PROP.$KEY ...>)
- pattern: |
useState(function $X(...) {
...
<... $PROP ...>
...
})
- pattern: |
useState(function $X(...) {
...
<... $PROP.$KEY ...>
...
})
- metavariable-regex:
metavariable: $PROP
regex: ^(?!default|initial).*$
message: Copying a prop into state in React -- this is bad practice as all
updates to it are ignored. Instead, read props directly in your component
and avoid copying props into state.
metadata:
references:
- https://overreacted.io/writing-resilient-components/#principle-1-dont-stop-the-data-flow
category: best-practice
technology:
- react
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
languages:
- typescript
- javascript
severity: WARNING
Examples
react-props-in-state.jsx
class Test1 extends React.Component {
constructor() {
// ruleid:react-props-in-state
this.state = {
foo: 'bar',
color: this.props.color,
one: 1
};
}
render() {
const { color } = this.state;
return (
<button className={'Button-' + color}>
{this.props.children}
</button>
);
}
}
class Test2 extends React.Component {
constructor() {
// ruleid:react-props-in-state
this.state = {
textColor: slowlyCalculateTextColor(this.props.color)
};
}
render() {
return (
<button className={
'Button-' + this.props.color +
' Button-text-' + this.state.textColor
}>
{this.props.children}
</button>
);
}
}
class OkTest extends React.Component {
// ok: react-props-in-state
constructor() {
this.state = {
foo: 'bar',
initialColor: this.props.color,
one: 1
};
}
render() {
const { color } = this.state;
return (
<button className={'Button-' + color}>
{this.props.children}
</button>
);
}
}
function Test3({ text }) {
// ruleid:react-props-in-state
const [buttonText] = useState(text)
return <button>{buttonText}</button>
}
function Test4(props) {
// ruleid:react-props-in-state
const [formattedText] = useState(() => slowlyFormatText(props.text))
return <button>{formattedText}</button>
}
function OkTest1({ color, children }) {
const textColor = useMemo(
// ok: react-props-in-state
() => slowlyCalculateTextColor(color),
[color]
);
return (
<button className={'Button-' + color + ' Button-text-' + textColor}>
{children}
</button>
);
}
class OkTest2 extends React.PureComponent {
render() {
// ok: react-props-in-state
const textColor = slowlyCalculateTextColor(this.props.color);
return (
<button className={
'Button-' + this.props.color +
' Button-text-' + textColor
}>
{this.props.children}
</button>
);
}
}
react-props-in-state.tsx
class Test1 extends React.Component {
constructor() {
// ruleid:react-props-in-state
this.state = {
foo: 'bar',
color: this.props.color,
one: 1
};
}
render() {
const { color } = this.state;
return (
<button className={'Button-' + color}>
{this.props.children}
</button>
);
}
}
class Test2 extends React.Component {
constructor() {
// ruleid:react-props-in-state
this.state = {
textColor: slowlyCalculateTextColor(this.props.color)
};
}
render() {
return (
<button className={
'Button-' + this.props.color +
' Button-text-' + this.state.textColor
}>
{this.props.children}
</button>
);
}
}
class OkTest extends React.Component {
// ok: react-props-in-state
constructor() {
this.state = {
foo: 'bar',
initialColor: this.props.color,
one: 1
};
}
render() {
const { color } = this.state;
return (
<button className={'Button-' + color}>
{this.props.children}
</button>
);
}
}
function Test3({ text }) {
// ruleid:react-props-in-state
const [buttonText] = useState(text)
return <button>{buttonText}</button>
}
function Test4(props) {
// ruleid:react-props-in-state
const [formattedText] = useState(() => slowlyFormatText(props.text))
return <button>{formattedText}</button>
}
function OkTest1({ color, children }) {
const textColor = useMemo(
// ok: react-props-in-state
() => slowlyCalculateTextColor(color),
[color]
);
return (
<button className={'Button-' + color + ' Button-text-' + textColor}>
{children}
</button>
);
}
class OkTest2 extends React.PureComponent {
render() {
// ok: react-props-in-state
const textColor = slowlyCalculateTextColor(this.props.color);
return (
<button className={
'Button-' + this.props.color +
' Button-text-' + textColor
}>
{this.props.children}
</button>
);
}
}
function OkTest3({ initialText }) {
// ok: react-props-in-state
const [buttonText] = useState(initialText)
return <button>{buttonText}</button>
}
Short Link: https://sg.run/2bZz