React Pemasangan Komponen Dua Kali

Di dalam sebagian kecil aplikasi React/Redux/ReactRouterV4 saya, saya memiliki hierarki komponen berikut,

- Exhibit (Parent)
-- ExhibitOne
-- ExhibitTwo
-- ExhibitThree

Di dalam turunan Exhibit, ada sekitar 6 kemungkinan rute berbeda yang dapat dirender juga. Jangan khawatir, saya akan menjelaskannya dengan beberapa kode.

Inilah Komponen Pameran Induk saya:

export class Exhibit extends Component {
  render() {
    const { match, backgroundImage } = this.props

    return (
      <div className="exhibit">
        <Header />
        <SecondaryHeader />

        <div className="journey"
          style={{
            color: 'white',
            backgroundImage: `url(${backgroundImage})`,
            backgroundSize: 'cover',
            backgroundRepeat: 'no-repeat',
            backgroundPosition: 'center-center'
          }}>

          <Switch>
            <Route path={`${match.url}/exhibit-one`} component={ExhibitOne} />
            <Route path={`${match.url}/exhibit-two`} component={ExhibitTwo} />
            <Route path={`${match.url}/exhibit-three`} component={ExhibitThree} />
            <Redirect to="/" />
          </Switch>
        </div>
      </div>
    )
  }
}

Pada dasarnya, semua tugasnya adalah menampilkan salah satu subkomponen pameran, dan mengatur gambar latar belakang.

Berikut adalah salah satu subkomponennya, ExhibitOne:

export default class ExhibitOne extends Component {
  constructor(props) {
    super(props)
  }

  render() {
    const { match } = this.props

    return (
      <div className="exhibit-one">
        <Switch>
          <Route path={`${match.url}/wall-one`} component={ExhibitHOC(WallOne)} />
          <Route path={`${match.url}/wall-two`} component={ExhibitHOC(WallTwo)} />
          <Route path={`${match.url}/wall-three`} component={ExhibitHOC(WallThree)} />
          <Route path={`${match.url}/wall-four`} component={ExhibitHOC(WallFour)} />
          <Route path={`${match.url}/wall-five`} component={ExhibitHOC(WallFive)} />
          <Route path={`${match.url}/wall-six`} component={ExhibitHOC(WallSix)} />
        </Switch>
      </div>
    )
  }
}

Untuk mengurangi pengetikan, saya memutuskan untuk membungkus komponen dalam Komponen Tingkat Tinggi, yang tujuannya adalah untuk mengirimkan tindakan yang akan mengatur gambar latar belakang yang tepat pada komponen induk Pameran tingkat atas.

Ini adalah Komponen Tingkat Tinggi:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../actions/wall-background-image'

export default function(ComposedComponent) {
  class ExhibitHoc extends Component {

    componentDidMount = () => this.props.setBackgroundImage(`./img/exhibit-one/${this.getWall()}/bg.jpg`)

    getWall = () => {
      // this part isnt important. it is a function that determines what wall I am on, in order to set
      // the proper image.
    }

    render() {
      return <ComposedComponent />
    }
  }

  return connect(null, actions)(ExhibitHoc);
}

Pada pemuatan awal ExhibitOne, saya dapat melihat bahwa pembuat tindakan setBackgroundImage dijalankan dua kali dengan melihat Redux Logger di konsol. Kecenderungan awal saya untuk menggunakan komponenDidMount adalah karena menurut saya menggunakannya akan membatasi pembuat tindakan untuk mengeksekusi hanya sekali. Berikut tangkapan layar lognya:

masukkan deskripsi gambar di sini

Saya pikir saya mungkin salah memahami cara kerja Komponen Tingkat Tinggi, atau mungkin itu semacam React Router V4? Bagaimanapun, bantuan apa pun akan sangat dihargai mengapa ini dilakukan dua kali.


person Dan Zuzevich    schedule 01.03.2018    source sumber


Jawaban (3)


Masalahnya adalah prop component di sini adalah aplikasi fungsi, yang menghasilkan kelas baru pada setiap render. Hal ini akan menyebabkan komponen sebelumnya dilepas dan komponen baru dipasang (lihat dokumen untuk reaksi-router untuk informasi lebih lanjut). Biasanya Anda akan menggunakan prop render untuk menangani hal ini, tetapi ini tidak akan berfungsi dengan komponen tingkat tinggi, karena komponen apa pun yang dibuat dengan aplikasi HOC selama rendering akan tetap dipasang ulang selama rekonsiliasi React.

Solusi sederhana adalah dengan membuat komponen Anda di luar kelas ExhibitOne, misalnya:

const ExhibitWallOne = ExhibitHOC(WallOne);
const ExhibitWallTwo = ExhibitHOC(WallTwo);
..
export default class ExhibitOne extends Component {
  ..
          <Route path={`${match.url}/wall-one`} component={ExhibitWallOne} />
          <Route path={`${match.url}/wall-two`} component={ExhibitWallTwo} />
          ..
}

Alternatifnya, bergantung pada apa yang dilakukan pembungkusnya, dimungkinkan untuk mendeklarasikannya sebagai komponen normal yang merender {this.props.children} alih-alih parameter <ComposedComponent/>, dan membungkus komponen di setiap Route:

<Route path={`${match.url}/wall-one`}
       render={(props) => <Wrap><WallOne {...props}/></Wrap>}
/>

Perhatikan bahwa Anda harus menggunakan render alih-alih component untuk mencegah pemasangan ulang. Jika komponen tidak menggunakan props perutean, Anda bahkan dapat menghapus {...props}.

person Oblosys    schedule 01.03.2018
comment
Menembakkan beberapa kode ini ke editor teks saya sekarang. Akan segera membalas ›_‹ - person Dan Zuzevich; 01.03.2018
comment
Cemerlang! Menyelamatkan saya dari banyak rasa sakit di sini. Masuk akal sekarang setelah Anda menjelaskan bahwa ini menghasilkan kelas baru pada setiap render. - person Dan Zuzevich; 01.03.2018
comment
Senang bisa membantu :-) - person Oblosys; 01.03.2018
comment
Senang melihat ini masih membantu orang hingga saat ini. Jawaban yang bagus @Oblosys! - person Dan Zuzevich; 10.08.2020

Di sini pada tahun 2020, hal ini disebabkan oleh komponen <React.StrictMode> yang membungkus <App /> di versi baru Create React App. Menghapus komponen yang mengganggu dari index.js memperbaiki masalah pemasangan ganda untuk semua komponen saya. Saya tidak tahu apakah ini memang disengaja atau apa, tapi itu menjengkelkan dan menyesatkan melihat console.logs() dua kali untuk semuanya.

person SacWebDeveloper    schedule 06.06.2020
comment
Tangkapan yang bagus. Saya belum menyadarinya sebelumnya. Ajukan laporan bug mungkin? - person Dara Java; 21.10.2020
comment
Cemerlang! Menyelamatkan saya beberapa jam dari menggaruk kepala! Masuk akal bagi saya bahwa StrictMode akan berfungsi seperti ini, jadi saya ragu ini dapat dianggap sebagai bug. Namun, pemasangan ganda sangat tidak terduga, terutama ketika Anda tidak menyadari <React.StrictMode> ada di sana... mungkin menyenangkan melihat keluaran di konsol yang menunjukkan apa yang terjadi. - person Rolandus; 13.04.2021

Jika Anda menggunakan 'Reaksi UI Material Tersembunyi', komponen Anda akan dipasang setiap kali Anda memanggilnya. Misalnya, saya menulis yang di bawah ini:

<Hidden mdDown implementation="css">
    <Container component="main" maxWidth="sm">
        {content}
    </Container>
</Hidden>
<Hidden smUp implementation="css">
    {content}
</Hidden>

Itu memanggil kedua konten di kedua komponen tersembunyi. aku butuh banyak waktu.

person Mohammad    schedule 23.12.2019