Могу ли я изменить один дочерний компонент в цикле без повторного рендеринга всего списка? - PullRequest
1 голос
/ 11 октября 2019

У меня есть родительский компонент, где я зацикливаюсь на массиве продуктов и отрисовываю дочерний компонент внутри. Дочерний компонент содержит кнопку, которая должна обновлять только некоторые значения этого компонента, без повторного рендеринга всего списка.

import React, { useState } from "react";
import { connect } from "react-redux";
import ListComponent from "./ListComponent";
import Search from "./search";
import Loader from "./../Loader";

// import { getProductList } from "../../redux/actions/index";

const mapStateToProps = state => {
    return { list: state.product.productList, loading: state.product.loader };
};

const App = ({ list, loading }) => {
    const [products, setProducts] = useState(list);
    const handleButtonAction = data => {
        let newProductList = list.map((v, i) => {
            if (v.id === data.id) {
                v.isInCatalogue = true;
            }
            return v;
        });
        setProducts(newProductList);
        list = products;
    };

    return (
        <div className="container-fluid">
            {loading ? <Loader /> : ""}
            <div className="row d-flex mt-5">
                <div className="col-md-12 col-sm-12">
                    <Search />
                </div>
                <div className="col-md-12 col-sm-12">
                    <div className="row ">
                        {list.map((v, i) => {
                            if (v.isInCatalogue) {
                                v.iconClass = "fa fa-check text-success";
                            } else {
                                v.iconClass = "fa fa-plus";
                            }
                            return (
                                <div key={i} className="col-sm-6 col-md-4 mb-4 ">
                                    <ListComponent
                                        data={v}
                                        handleButtonAction={handleButtonAction}
                                    />

                                </div>
                            );
                        })}
                    </div>
                </div>
            </div>
        </div>
    );
};

export default connect(mapStateToProps)(App);

Ответы [ 3 ]

1 голос
/ 11 октября 2019

Поскольку вы делаете неизменное изменение своего списка (правильно), перерисовка всего списка неизбежна.

Функциональная перерисовка компонента без сохранения состояния также, когда его реквизиты не изменились (если вы не используете React.memoкак предложил @AspirinWang), см. этот ответ:

Будет ли компонент без состояния повторно визуализироваться, если его реквизиты не изменились?

Назначение ключей в реакции точно разработаны для этой ситуации. Если ваши не обновленные (и также обновленные) элементы имеют один и тот же ключ до и после изменения, это нормально и не беспокоит повторного отображения (если ваш элемент списка не содержит огромное дерево JSX).

Этохорошо знать, что рендеринг callig для любого компонента не является проблемой, и целевое создание компонента, чтобы не делать рендеринг, не должно быть вашей целью (особенно функциональные компоненты без состояния), потому что:

Это важнопомнить, что алгоритм согласования является деталью реализации. React может перерисовывать все приложение при каждом действии;конечный результат будет таким же.

1 голос
/ 11 октября 2019
function ListComponent(props) {
  /* render using props */
}
function areEqual(prevProps, nextProps) {
  /*
  return true if passing nextProps to render would return
  the same result as passing prevProps to render,
  otherwise return false
  */
}
export default React.memo(ListComponent, areEqual);
0 голосов
/ 11 октября 2019

React не будет повторно визуализировать компонент, если выходные данные не отличаются, более того, в этом случае в listComponent, сохраните данные в качестве состояния и используйте useEffect с данными в качестве зависимости.

Что-токак ниже

const ListComponent = ({data})=>{
  const [compData, setCompData] = useState(data);

  useEffect(()=>{
    setCompData(data)
  },[data])

  return (
    <h1>{compData}</h1>
  )
}
...