简体   繁体   English

React.memo()重置状态

[英]React.memo() resets state

I have some inputs which I render from an array of objects. 我有一些输入是从对象数组中渲染的。

When I type in one input, I map over the array, find the corresponding object and set the input value. 当我输入一个输入时,我会在数组上映射,找到对应的对象并设置输入值。

The problem: Type some characters in one input, change input, type characters. 问题:在一个输入中键入一些字符,更改输入,键入字符。 Repeat this and observe the previous inputs are cleared and sometimes some random character appears in some inputs. 重复此步骤,观察先前的输入已清除,有时某些输入中会出现一些随机字符。

What is causing this behavior? 是什么导致此行为?

If I remove the React.memo() from SearchBar, the problem does not appear anymore. 如果我从SearchBar删除React.memo(),该问题不再出现。

What do I need to do to make it work with React.memo(). 我需要怎么做才能使其与React.memo()一起工作。

const shouldSkipComponentUpdate = (prevProps, props) =>
prevProps.value === props.value;

const SearchBar = React.memo((props) => {
  const { label, width, hasSearch, handleSearchChange, value } = props;
    return (
      <div width={width} style = { { margin: "15px", display: "inline" } }>
        {label}
        {hasSearch && (
          <SearchInput
            onChange={handleSearchChange}
            value={value}
            label={label}
          />
        )}
      </div>
    );
  }, (prevProps, props) => shouldSkipComponentUpdate(prevProps, props));


function DevicesContainer() {
  const [searchBoxes, setSearchBoxes] = React.useState(() => {
    return [
      {
        id: 1,
        label: '',
        width: '5%',
        hasSearch: false,
        value: ''
      },
      {
        id: 2,
        label: 'ID',
        width: '5%',
        value: '',
        hasSearch: false
      },
      {
        id: 3,
        width: '10%',
        label: 'Name',
        value: '',
        hasSearch: true
      },
      {
        id: 4,
        width: '10%',
        label: 'Owner',
        value: '',
        hasSearch: true
      },
      {
        id: 5,
        width: '7%',
        label: 'Availability',
        value: '',
        hasSearch: false
      },
      {
        id: 6,
        width: '10%',
        label: 'Location',
        value: '',
        hasSearch: true
      },
      {
        id: 7,
        width: '20%',
        label: 'Environment',
        value: '',
        hasSearch: true
      },
      {
        id: 8,
        width: '10%',
        label: 'Firmware',
        value: '',
        hasSearch: true
      },
    ];
  });
  function handleSearchChange(event, label) {
    const {
      target: { value }
    } = event;
    const updated = searchBoxes.map(elem => {
      if (elem.label === label) {
        return { ...elem, value };
      }
      return elem;
    });
    setSearchBoxes(updated);
  }
  return (
    <main>
      <SearchBars
        searchBars={searchBoxes}
        handleSearchChange={handleSearchChange}
        />
    </main>
  );
}

function SearchBars(props) {
  const { searchBars, handleSearchChange } = props;
  return (
    <div style={ { margin: '20px' } }>
      {searchBars.map(elem => (
        <SearchBar
          key={elem.id}
          label={elem.label}
          width={elem.width}
          hasSearch={elem.hasSearch}
          value={elem.value}
          handleSearchChange={handleSearchChange}
          />
      ))}
    </div>
  );
}

function SearchInput(props) {
  const { onChange, value, label } = props;
  return (
    <input
      type="search"
      value={value}
      placeholder="Search"
      onChange={event => onChange(event, label)}
      />
  );
}

  ReactDOM.render(
    <DevicesContainer />,
    document.getElementById('root')
  );


codepen link https://codepen.io/Apoptotic/pen/ZdPpQG codepen链接https://codepen.io/Apoptotic/pen/ZdPpQG

You can change the handleSearchChange() function. 您可以更改handleSearchChange()函数。 See the docs on the setState behaviour. 请参阅有关setState行为的文档 You might also note, that this function runs asynchronously. 您可能还注意到,该函数异步运行。 I just moved the mapping function into the setSearchBox update handle to apply the data to the previous state. 我只是将映射功能移到了setSearchBox更新句柄中,以将数据应用于先前的状态。

  function handleSearchChange(event, label) {
    const {
      target: { value }
    } = event;


    setSearchBoxes((prevSearchBoxes) => {
      let s = [...prevSearchBoxes];
      let updated = s.map(elem => {
        if (elem.label === label) {
          return { ...elem, value };
        }
        return elem;
      });
      return updated;
    });
  }

Additionally see the following note from the React Docs. 另外,请参阅React Docs中的以下说明。

Unlike the setState method found in class components, useState does not automatically merge update objects. 与在类组件中找到的setState方法不同,useState不会自动合并更新对象。 You can replicate this behavior by combining the function updater form with object spread syntax: 您可以通过将函数更新程序形式与对象传播语法结合使用来复制此行为:

setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});

Another option is useReducer, which is more suited for managing state objects that contain multiple sub-values. 另一个选择是useReducer,它更适合于管理包含多个子值的状态对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM