Here is my summary for the article “ Common Beginner Mistakes with React ” by Josh W. Comeau. Please visit the author’s original blog to read the English version.
Error 1: Comparison with 0
Let’s say you have a list of items and will render if there is at least one element.
const [items, setItems] = React.useState([]);
Would you write it like this expecting to be visible only when the list has an element:
1 2 3 4 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> items <span class="token punctuation">.</span> length <span class="token operator">&&</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> <span class="token class-name">ShoppingList</span></span> <span class="token attr-name">items</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> items</span> <span class="token punctuation">></span></span> <span class="token plain-text">} </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> |
However, when items has no elements, a number 0. Why is that?
When items.length has the value 0 which is a falsy value in JS, the && combination results in 0.
In JSX, 0 is a valid value, so it is built into the UI.
Fix 1: using comparison returns boolean as true/false
1 2 3 4 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> items <span class="token punctuation">.</span> length <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&&</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> <span class="token class-name">ShoppingList</span></span> <span class="token attr-name">items</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> items</span> <span class="token punctuation">></span></span> <span class="token plain-text">} </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> |
Fix 2: return null if no element
1 2 3 4 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> items <span class="token punctuation">.</span> length <span class="token operator">?</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> <span class="token class-name">ShoppingList</span></span> <span class="token attr-name">items</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> items</span> <span class="token punctuation">></span></span><span class="token plain-text"> : null} </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> |
Error 2: Change the value of state
Suppose you need to add an element, in the handler function when adding the section, you might have done:
1 2 3 4 5 | <span class="token keyword">function</span> <span class="token function">handleAddItem</span> <span class="token punctuation">(</span> <span class="token parameter">value</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> items <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> value <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setItems</span> <span class="token punctuation">(</span> items <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Result : adding an element no element is built into the UI.
The problem : this code violates the core principle of React, the value of state must not be changed.
How to fix: need to create a new array for the changelist and then assign the value state
1 2 3 | <span class="token keyword">const</span> nextItems <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token operator">...</span> items <span class="token punctuation">,</span> value <span class="token punctuation">]</span> <span class="token function">setItems</span> <span class="token punctuation">(</span> nextItems <span class="token punctuation">)</span> |
Error 3: Did not generate key when rendering element in list
When you render the list of elements:
1 2 3 4 5 6 | <span class="token punctuation">{</span> items <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">item</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> li</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> item <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> li</span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
there will be an error saying “Warning: Each child in a list should have a unique “key” prop.”
You will need to provide context for React to distinguish between elements, by providing keys with unique values.
Error 4: Missing spaces
For example:
1 2 3 4 5 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span><span class="token plain-text"> Welcome to blog! <a href=“/login”> Log in to continue </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> a</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> |
Result: Welcome to blog!Log in to continue
How to fix: add a space {' '}
between two lines.
Error 5: Accessing state value after change
Suppose to print out state items after changing the state from the original items [] as follows:
1 2 3 | <span class="token function">setItems</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> …items <span class="token punctuation">,</span> value <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> items <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
then the result displayed on the screen is an added element.
But in console the result is still []
Reason : the setItems() function is asynchronous, meaning it doesn’t immediately change the value, but is only scheduled to update this state. Therefore, this change takes a certain time to complete.
How to fix: use an intermediate variable to access
1 2 3 4 | <span class="token keyword">const</span> nextItems <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token operator">...</span> items <span class="token punctuation">,</span> value <span class="token punctuation">]</span> <span class="token function">setItems</span> <span class="token punctuation">(</span> nextItems <span class="token punctuation">)</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> nextItems <span class="token punctuation">)</span> |
Error 6: Returning multiple components in component
Sometimes you will need to return multiple elements, for example a label tag and an input.
If you write something like this:
1 2 3 4 5 | <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span> label <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> label <span class="token operator">></span> <span class="token operator"><</span> input <span class="token operator">/</span> <span class="token operator">></span> <span class="token punctuation">)</span> |
it will give the error “Adjacent JSX elements must be wrapped in an enclosing tag.”
Reason : JSX elements need to be wrapped by a collapsible tag pair.
Bug fix : use <React.Fragment></React.Fragment>
, or <></>
for short
Error 7: Moving component from uncontrolled to controlled
Assuming the input is email, when changing the value will reset the state for the email variable
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">const</span> <span class="token punctuation">[</span> email <span class="token punctuation">,</span> setEmail <span class="token punctuation">]</span> <span class="token operator">=</span> React <span class="token punctuation">.</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// …</span> <span class="token operator"><</span> input id <span class="token operator">=</span> “email <span class="token operator">-</span> input” type <span class="token operator">=</span> “email” value <span class="token operator">=</span> <span class="token punctuation">{</span> email <span class="token punctuation">}</span> onChange <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token function">setEmail</span> <span class="token punctuation">(</span> e <span class="token punctuation">.</span> target <span class="token punctuation">.</span> value <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> |
When you enter a value into the input, you will get an error “Warning: A component is changing an uncontrolled input to be controlled”
The reason is that the email state variable has no initial value, so the value is undefined. And when I assigned value={email} I told React this is an uncontrolled component.
However, when you change the state, you want it to act as a controlled component, so it will cause an error.
How to fix: make sure email with initial value is not undefined const [email, setEmail] = React.useState('');
Error 8: Missing {} for code style
In CSS, the style attribute uses style
1 2 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> button</span> <span class="token special-attr"><span class="token attr-name">style</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token value css language-css"><span class="token property">“color</span> <span class="token punctuation">:</span></span></span></span> <span class="token attr-name">red;</span> <span class="token attr-name"><span class="token namespace">font-size:</span></span> <span class="token attr-name">1em”</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> button</span> <span class="token punctuation">></span></span> |
But in JSX, the style attribute needs to be wrapped by {}, and the values are written in the object’s syntax. { color: 'red', fontSize: '1em' }
And since it’s a value of the style attribute, an extra pair of {} is needed to represent that.
1 2 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> button</span> <span class="token attr-name">style</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> color <span class="token operator">:</span> <span class="token string">'red'</span> <span class="token punctuation">,</span> fontSize <span class="token operator">:</span> <span class="token string">'1em'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> button</span> <span class="token punctuation">></span></span> |
If you want more clarity, you can create a separate variable for the style and then use:
1 2 3 | <span class="token keyword">const</span> btnStyle <span class="token operator">=</span> <span class="token punctuation">{</span> color <span class="token operator">:</span> “red” <span class="token punctuation">,</span> fontSize <span class="token operator">:</span> ‘ <span class="token number">1</span> em’ <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> button</span> <span class="token attr-name">style</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> btnStyle <span class="token punctuation">}</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> button</span> <span class="token punctuation">></span></span> |
Error 9: Async effect function
Assuming you need to call an API that returns a list of items, you use the useEffect hook and await as follows:
1 2 3 4 5 6 7 | React <span class="token punctuation">.</span> <span class="token function">useEffect</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span> <span class="token punctuation">(</span> “ <span class="token operator">/</span> api <span class="token operator">/</span> v1 <span class="token operator">/</span> items” <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> json <span class="token operator">=</span> <span class="token keyword">await</span> res <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setItems</span> <span class="token punctuation">(</span> json <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
The above code will cause an error because await is only used with async functions. Even if you add async like this, you will still get the error:
1 2 3 4 5 6 7 | React <span class="token punctuation">.</span> <span class="token function">useEffect</span> <span class="token punctuation">(</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span> <span class="token punctuation">(</span> “ <span class="token operator">/</span> api <span class="token operator">/</span> v1 <span class="token operator">/</span> items” <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> json <span class="token operator">=</span> <span class="token keyword">await</span> res <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setItems</span> <span class="token punctuation">(</span> json <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
How to fix: write a separate async function for invoke
1 2 3 4 5 6 7 8 9 10 11 12 | React <span class="token punctuation">.</span> <span class="token function">useEffect</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// create async function</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">runEffect</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span> <span class="token punctuation">(</span> “ <span class="token operator">/</span> api <span class="token operator">/</span> v1 <span class="token operator">/</span> items” <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> json <span class="token operator">=</span> <span class="token keyword">await</span> res <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setItems</span> <span class="token punctuation">(</span> json <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// invoke it</span> <span class="token function">runEffect</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Reason : the async function returns a promise, but the useEffect hook can’t handle the return promise, so we need to move the async function separately and call it so that the function in useEffect is clean.
Summary article from this blog , please read and support the author
This Vietnamese article is reposted from the original BeautyOnCode blog post .