Search code examples
javascripthtmlreactjsreact-hooksreact-custom-hooks

Invalid value for prop `reset` on <input> tag


I was getting this warning:

react-dom.development.js:86 Warning: Invalid value for prop reset on tag. Either remove it from the element, or pass a string or number value to keep it in the DOM. For details, see https://reactjs.org/link/attribute-behavior

This came from my custom hook:

import { useState } from 'react'

export const useField = (type) => {
  const [value, setValue] = useState('')

  const onChange = (event) => {
    setValue(event.target.value)
  }

  const reset = () => {
    setValue('')
  }

  return {
    type,
    value,
    onChange,
    reset
  }
}

The hook is used in a component:

const CreateNew = (props) => {
  const content = useField('text')
  const author = useField('text')
  const info = useField('text')

  const navigate = useNavigate()

  const handleSubmit = (e) => {
    e.preventDefault()

    props.addNew({
      content: content.value,
      author: author.value,
      info: info.value,
      votes: 0
    })
    navigate('/')
    props.setNotification(`a new anecdote ${content.value} created!`)
    setTimeout(() => {
      props.setNotification(null)
    }, 5000)
  }

  const handleReset = (event) => {
    console.log(content)
    content.onReset()
    author.onReset()
    info.onReset()
  }

  return (
    <div>
      <h2>create a new anecdote</h2>
      <form onSubmit={handleSubmit}>
        <div>
          content
          <input {...content} />
        </div>
        <div>
          author
          <input {...author} />
        </div>
        <div>
          url for more info
          <input {...info} />
        </div>
        <button type="submit">create</button>
        <button type="button" onClick={handleReset}>reset</button>
      </form>
    </div>
  )
}

The warning disappeared when I change the name of the function reset to onReset, but I don't understand why.

Is onReset a special keyword for react or something? I changed it on pure luck and the problem was gone but I don't get why.


Solution

  • Issue

    You are passing a reset prop/attribute to an input element that is an invalid attribute value, it's a function, not a string or a number.

    const useField = (type) => {
      const [value, setValue] = useState("");
    
      const onChange = (event) => {
        setValue(event.target.value);
      };
      const reset = () => {
        setValue("");
      };
    
      return {
        type,
        value, // <-- is a function
        onChange,
        reset
      };
    };
    

    ...

    const content = useField('text'); // <-- includes reset function
    

    ...

    <input {...content} /> // <-- reset spread to input, causes error
    

    See input tag for a list of valid attributes.

    The reason React doesn't flag the name onReset is because this is a valid event handler (but for form elements, not input), see Synthetic Events.


    Your Question

    Is onReset a special keyword for react or something? I changed it on pure luck and the problem was gone but I don't get why.

    If you follow the link in the warning, buried in the page is this note.

    Note: attributes starting with on are not passed through as an exception because this could become a potential security hole.


    Additionally there's an issue in the handleReset callback that is referencing undefined properties and attempting to invoke them, which will obviously throw an error when the preceding issues are resolved.

    const handleReset = (event) => {
      console.log(content);
      content.onReset(); // <-- onReset is undefined, should call content.reset()
      author.onReset();
      info.onReset();
    };
    

    Solution

    Destructure the reset function from the useField hook's return value and spread the rest into a props object. Reference the correct reset function in handleReset.

    Example:

    const CreateNew = (props) => {
      const { reset: resetContent, ...content } = useField("text");
      const { reset: resetAuthor, ...author } = useField("text");
      const { reset: resetInfo, ...info } = useField("text");
    
      ...
    
      const handleReset = (event) => {
        console.log(content);
        resetContent();
        resetAuthor();
        resetInfo();
      };
    
      return (
        <div>
          <h2>create a new anecdote</h2>
          <form onSubmit={handleSubmit}>
            <div>
              content
              <input {...content} />
            </div>
            <div>
              author
              <input {...author} />
            </div>
            <div>
              url for more info
              <input {...info} />
            </div>
            <button type="submit">create</button>
            <button type="button" onClick={handleReset}>
              reset
            </button>
          </form>
        </div>
      );
    };
    

    Edit invalid-value-for-prop-reset-on-input-tag