当我在反应中重新排序表时,“孩子已经有一个父母,必须先将其删除”

ver*_*thS 7 javascript reactjs

我正在尝试在反应中指定一个材料反应表。

在我需要排序的列中,我放置了这个函数:

<TableCell onClick={() => sortBy('login')}>Email</TableCell>

const sortBy = (key) => {
    // If is using a field different by the last, starts ordering in asc
    if (key !== orderingField) {
        setOrderingStatus('asc')
        setOrderingField(key)
    // Reverte a ordenação
    } else { 
        if (orderingStatus === 'asc') {
            setOrderingStatus('desc')
        } else {
            setOrderingStatus('asc')
        }
    }
    let copyUsers = {}
    copyUsers.data = [...users] // make a copy of the obj
    copyUsers.lastPage = JSON.parse(JSON.stringify(lastPage)) // copy of the last page 
    copyUsers.data.sort(compareValues(orderingField, orderingStatus)) // make the sort)
    dispatch(userActions.setUserList(copyUsers))
}
Run Code Online (Sandbox Code Playgroud)

这是我订购的功能:

export default function compareValues(key, order = 'asc') {
    return function innerSort(a, b) {
      if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
        // property doesn't exist on either object
        return 0;
      }

      const varA = (typeof a[key] === 'string')
        ? a[key].toUpperCase() : a[key];
      const varB = (typeof b[key] === 'string')
        ? b[key].toUpperCase() : b[key];

      let comparison = 0;
      if (varA > varB) {
        comparison = 1;
      } else if (varA < varB) {
        comparison = -1;
      }
      return (
        (order === 'desc') ? (comparison * -1) : comparison
      );
    };
}
Run Code Online (Sandbox Code Playgroud)

当我在我的减速器中看到请求有效负载像预期的那样到来时,排序已经完成,但这不会再次呈现我的表,我得到了一些错误:

孩子已经有父母,必须先将其删除。

nbind.js:9812 未捕获 abort()

我正在使用这个 reduxuseSelector()从商店中获取我的表的值:

const users = useSelector(state => state.userStates.users)
Run Code Online (Sandbox Code Playgroud)

所以在我的表中,我显示迭代:

{users && users.map(user => (
Run Code Online (Sandbox Code Playgroud)

有人可以告诉我为什么会这样吗?

经过非常艰难的调试后,我发现问题出在 obj 的副本中。当我使用参考进行复制时,例如:

copyUsers.data = users
Run Code Online (Sandbox Code Playgroud)

一切正常,但是当我尝试没有参考的副本时,例如:

copyUsers.data = JSON.parse(JSON.stringify(users))
Run Code Online (Sandbox Code Playgroud)

或者

copyUsers.data = [...users]
Run Code Online (Sandbox Code Playgroud)

我收到错误。

有人可以解释一下吗?

我的 package.json 依赖项:

"dependencies": {
    "@material-ui/core": "4.9.5",
    "@material-ui/icons": "^4.9.1",
    "@material-ui/lab": "^4.0.0-alpha.45",
    "@react-pdf/renderer": "^1.6.8",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "axios": "^0.19.2",
    "formik": "^2.1.4",
    "immer": "^6.0.1",
    "notistack": "^0.9.8",
    "react": "^16.13.0",
    "react-dom": "^16.13.0",
    "react-export-excel": "^0.5.3",
    "react-history": "^0.18.2",
    "react-html2pdf": "^1.0.1",
    "react-input-mask": "^2.0.4",
    "react-redux": "^7.2.0",
    "react-router-dom": "^5.1.2",
    "react-scripts": "3.4.0",
    "redux": "^4.0.5",
    "redux-saga": "^1.1.3",
    "styled-components": "^5.0.1",
    "yup": "^0.28.1"
  },
Run Code Online (Sandbox Code Playgroud)

我的pdf组件:

<Grid item>
    <UsersPDF />
</Grid>
Run Code Online (Sandbox Code Playgroud)

这是我的用户PDF:

class UsersPDF extends Component {

    constructor(props) {
        super(props);
        this.state = {
            ready: false
        };
    }

    componentDidMount() {
        this.setState(
            () => ({
                ready: false
            }),
            () => {
                setTimeout(() => {
                    this.setState({ ready: true });
                }, 1);
            }
        );
    }

    render() {
        const { users } = this.props;
        const { ready } = this.state;

        const doc = (
            <Document>
                <Page style={styles.body}>
                    <View style={styles.rowCabecalho}>
                        <Text style={styles.nomeRelatorio}>Relatório de usuários</Text>
                    </View>
                    <View style={styles.table}>
                        <View style={styles.tableRow}>
                            <View style={styles.tableCol}>
                                <Text style={styles.tableCell}>Email</Text>
                            </View>
                            <View style={styles.tableCol}>
                                <Text style={styles.tableCell}>
                                    Filial logada
                                </Text>
                            </View>
                            <View style={styles.tableCol}>
                                <Text style={styles.tableCell}>Ativo</Text>
                            </View>
                        </View>
                        {users && users.map(user => (
                        <View key={user.id} style={styles.tableRow}>
                            <View style={styles.tableCol}>
                                <Text style={styles.tableCell}>{user.login}</Text>
                            </View>
                            <View style={styles.tableCol}>
                                <Text style={styles.tableCell}>{user.company_name}</Text>
                            </View>
                            <View style={styles.tableCol}>
                                <Text style={styles.tableCell}>
                                    {user.inactive === true ? 'Não' : 'Sim'}
                                </Text>
                            </View>
                        </View>
                        ))}
                    </View>
                </Page>
            </Document>
        );

        return (
            <>
                {ready && (
                    <PDFDownloadLink style={{textDecoration: 'none'}} className={styles.PDFDownloadLink} document={doc} fileName="usuarios.pdf">
                        {({ blob, url, loading, error }) =>
                            loading ? <></> : <Button variant="contained" color="primary">PDF</Button>
                        }
                    </PDFDownloadLink>
                )}
            </>
        );
    }
}

const mapStateToProps = state => ({
    users: state.userStates.users
});

export default connect(mapStateToProps)(UsersPDF);
Run Code Online (Sandbox Code Playgroud)

Tro*_*bol 4

编辑2:这是一个已知错误,对此问题有一些解决方法。

我相当确定错误出在另一个组件中,这个 github 问题(位于@react-pdf/renderer)似乎与您遇到的问题相同。他们说它第一次有效,但Child already has a parent, ...之后抛出错误。

(我认为)发生的情况是当state.userStates.users更新时,使用的组件@react-pdf/renderer会更新并泄漏内存,从而导致错误。

当您不克隆数组时,不会发生这种情况,因为 redux/react 不会将其注册为状态更改,因此组件不会重新渲染。

来自 github 上@willywill解决方案

const renderToStream = async function (element) {
  const instance = pdf(element);
  const buffer = await instance.toBuffer(); 
  instance.container.finish(); // This cleans up objects from memory (ADD ME)
  return buffer;
};
Run Code Online (Sandbox Code Playgroud)

编辑:如果您正在使用,renderToStream请务必使用@react-pdf/renderer >=1.5.6,因为它修复了此错误。(错误修复1.5.6 版本