2

Scenario

I declared a react component that renders a simple html input tag.

const MyComponent = (props) => (
  <input
    defaultValue="test"
    onChange={(e) => {
      props.setTitle(e.target.value);
    }}
  />
);

Then I declared a function that takes a setState as a parameter and returns that component with the setState inside the input's onChange.

const getComponent = (setTitle) => (props) => (
  <input
    defaultValue="test"
    onChange={(e) => {
      setTitle(e.target.value);
    }}
  />
);

Then I called my function to get the component and to render it:

const Root = () => {
  const [title, setTitle] = React.useState('');
  const Component = getComponent(setTitle);
  return (
    <div>
      <div>{title}</div>
      <Component />{' '}
    </div>
  );
};

Expected: The input element behaves normally, and changes its value

Reality: The input loses focus after each character typed, and won't retain its value.

Here is a simple example of the error: CodeSandbox

2
  • When you update the state of a component, it re-renders, which might lead to the behaviour you're describing Commented Nov 12, 2020 at 19:11
  • When i use the component directly instead of getting it from the getComponent function it works as expected even if the state changes. I don't understand why it isn't the same behaviour when i get it from a function Commented Nov 12, 2020 at 19:14

2 Answers 2

3

The reason this is happening is that when your code comes to this line:

const Component = getComponent(setTitle);

This generates new function (i.e. new instance) that is not rendered again, but mounted again. That is the reason you get unfocused from field.

There is no way you will make this work in this way, it's just not meant to be working like this. When you do it once when you are exporting it, than its ok, but every time === new instance.

If this is just an experiment that you are trying, than ok. But there is no reason not to pass setState as prop to that component.

Sign up to request clarification or add additional context in comments.

3 Comments

i'm making a High Order Component, that needs to do some things to the setState before passing it up to Component.
This isn't far off from what a higher order component is, where you have a function return a component. If you were to move the const Component = getComponent(setTitle); line outside of the component, it would not remount each render, but then setTitle goes out of scope and you're still left with a problem.
When using HOC, that is usually made outside component render code i.e. when you make component with HOC, and either store it inside const or export it from file. But since your Root component gets rerendered from time to time based on its state, you will get new component every time
0

I found a solution that let me use the function and keep the component from mounting each time.

If you put the function call inside the jsx, the component won't remount each render.

const Root = () => {
  const [title, setTitle] = React.useState('');
  const Component = ;
  const someprops = {};
  return (
    <div>
      <div>{title}</div>
      {getComponent(setTitle)(someprops)}
    </div>
  );
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.