Это хороший шаблон для сохранения реактивного элемента в useState для хорошей производительности? - PullRequest
1 голос
/ 13 марта 2020

Мы считаем, что это займет хорошее представление. Элементы не будут отображаться.

function App() {
  const [items, setItems] = useState(() => [<Counter key={0} i={0} />]);
  const onClick = () => {
    setItems([...items, <Counter key={items.length} i={items.length} />]);
  };

  return (
    <div className="App" onClick={onClick}>
      <h1>Hello CodeSandbox</h1>
      {items}
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

function Counter({ i }) {
  console.log(`render ${i}`);

  return <h2>{i}</h2>;
}

Для лучшего понимания я приведу пример в кодах и в поле: https://codesandbox.io/s/busy-austin-qbtpm

Ответы [ 2 ]

1 голос
/ 13 марта 2020

Чтобы предотвратить рендеринг, вы можете использовать чистый компонент или React.memo и убедиться, что вы никогда не передадите новую ссылку в качестве реквизита с помощью useCallback или useMemo. Вот пример:

const id = (i => () => ++i)(0);
function App() {
  const [items, setItems] = React.useState([]);
  const addCounter = React.useCallback(
    () =>
      setItems(items =>
        items.concat({
          id: id(),
          count: 0,
        })
      ),
    []
  );
  const add = React.useCallback(
    id =>
      setItems(items =>
        items.map(item =>
          item.id === id
            ? { ...item, count: item.count + 1 }
            : item
        )
      ),
    []
  );

  return (
    <div>
      <button onClick={addCounter}>Add counter</button>
      {items.map(item => (
        <Counter item={item} key={item.id} add={add} />
      ))}
    </div>
  );
}

const Counter = React.memo(function Counter({ item, add }) {
  console.log(`render ${item.id}`);

  return (
    <button onClick={() => add(item.id)}>
      {item.count}
    </button>
  );
});


//render app
ReactDOM.render(
  <App />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
1 голос
/ 13 марта 2020

Не очень хорошая идея хранить jsx в таком состоянии, как сказал Шон Яп. Но в целом с javascript это плохая практика. В этом случае это сложнее, чем нужно. Хорошей идеей является сделать данные как можно более простыми и легкими, а затем добавлять их при необходимости. В этом примере есть несколько улучшений, которые вы можете сделать

// You used both function App() & const onClick = () =>
// Best to choose one and stick with it. 
const App = () => {
  const [items, setItems] = useState([]);
  const onClick = () => {
    setItems([
      ...items,
      items.length
    ]);
  };

  return (
    <div className="App" onClick={onClick}>
      <h1>Hello CodeSandbox</h1>
      // Instead use a map to render items, you also don't need another function for this
      {items.map((item, index) => {
        console.log("rendered item with index: ", index)
        return <h2 key={index}>{index}</h2>
      })}
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

Также никогда не храните ключ элемента, ключ элемента которого основан на индексе. Хотя они могут выглядеть одинаково, если вы удалите элемент в своем примере, а затем добавите новый элемент, у вас будет ошибка. [1, 3, 3] сделал бы ошибку для вас. [1, 3, 3] использование индекса массива в качестве ключа не приведет к ошибке.

Надеюсь, что это поможет и удачного кодирования:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...