Search code examples
javascriptreactjsonbluronfocus

How can I combine onBlur and onFocus in my React Component without reselecting the text on every letter I type in?


I have a simple text input that looks like this:

<input
    type="text"
    value={listTitle}
    onChange={handleChange}
    autoFocus
    onFocus={handleFocus}
    onBlur={handleFinishEditing}
/>

handleFocus does just this e.target.select()

onBlur does just dispatch an action. (and sets the state so it doesn't show the input anymore)

The problem is with the handleFocus I think together with onBlur it doesn't quite work good together.

Everytime I type in the textfield it is just writing one letter and reselecting that letter. So it's like on every change the onSelect runs.

When I get rid of the onFocus prop everything works as expected (simple react controlled input - where it gets the value from state, and sets the state onChange).

Why is this happening and how can I prevent it?

I tried out different e.preventDefaulton the functions but neither worked. I mean when I'm just typing in something in text field the onBlur shouldn't even run. But the onSelect does, but I just want to run this when the component (the input) gets rendered initially.

Here is an example of how it should be: https://codesandbox.io/s/7y66ykqn2q?fontsize=14

This is the repo Branch: CRUD : https://github.com/SelfDevTV/trello-clone/tree/CRUD

This is the same code I use on github but to play around with in Codesandbox: https://codesandbox.io/s/q3o7zjjjqw

Thx in advance guys!


Solution

  • Ok guys I fixed it. The bug came from styled-components The bug was related to this part of the docs:

    https://www.styled-components.com/docs/basics#coming-from-css

    "Define Styled Components outside of the render method"

    At first the component looked like this:

    const TrelloList = ({ title, cards, listID, index, dispatch }) => {
      const [isEditing, setIsEditing] = useState(false);
      const [listTitle, setListTitle] = useState(title);
    
    
    
      const StyledInput = styled.input`
      width: 100%;
      border: none;
      outline-color: blue;
      border-radius: 3px;
      margin-bottom: 3px;
      padding: 5px;
    `;
    
      const renderEditInput = () => {
        return (
          <StyledInput
            type="text"
            value={listTitle}
            onChange={handleChange}
            autoFocus
            onFocus={handleFocus}
            onBlur={handleFinishEditing}
          />
        );
      };
    
      // other stuff
    

    Now I changed it to look like this:

    const StyledInput = styled.input`
      width: 100%;
      border: none;
      outline-color: blue;
      border-radius: 3px;
      margin-bottom: 3px;
      padding: 5px;
    `;
    
    const TrelloList = ({ title, cards, listID, index, dispatch }) => {
      const [isEditing, setIsEditing] = useState(false);
      const [listTitle, setListTitle] = useState(title);
    
    
    
      const renderEditInput = () => {
        return (
          <StyledInput
            type="text"
            value={listTitle}
            onChange={handleChange}
            autoFocus
            onFocus={handleFocus}
            onBlur={handleFinishEditing}
          />
        );
      };
    
      // other stuff
    

    This fixes the problem completely and thefore the node doesn't get deleted on every rerender. So this was my fault and I should have read the styled-components docs more in depth.