Bagaimana cara menambahkan atribut ke Bereaksi komponen secara kondisional?

551

Apakah ada cara untuk hanya menambahkan atribut ke komponen Bereaksi jika kondisi tertentu terpenuhi?

Saya seharusnya menambahkan atribut yang diperlukan dan readOnly untuk membentuk elemen berdasarkan panggilan Ajax setelah render, tapi saya tidak bisa melihat bagaimana menyelesaikannya karena readOnly = "false" tidak sama dengan menghilangkan atribut sepenuhnya.

Contoh di bawah ini harus menjelaskan apa yang saya inginkan, tetapi itu tidak akan berfungsi (Parse Error: Unexpected identifier).

var React = require('React');

var MyOwnInput = React.createClass({
    render: function () {
        return (
            <div>
                <input type="text" onChange={this.changeValue} value={this.getValue()} name={this.props.name}/>
            </div>
        );
    }
});

module.exports = React.createClass({
    getInitialState: function () {
        return {
            isRequired: false
        }
    },
    componentDidMount: function () {
        this.setState({
            isRequired: true
        });
    },
    render: function () {
        var isRequired = this.state.isRequired;

        return (
            <MyOwnInput name="test" {isRequired ? "required" : ""} />
        );
    }
});
Remi Sture
sumber
1
Mungkin satu komentar membantu seseorang, saya menemukan Bereaksi 16.7 tidak rerenders dan memperbarui atribut html komponen jika Anda hanya mengubah mereka di toko (fe redux) dan terkait dengan komponen. Ini berarti komponen memiliki fitur aria-modal=true, Anda mendorong perubahan (ke false) ke penyimpanan atribut aria / data , tetapi tidak ada yang lain yang diubah (seperti konten komponen atau kelas atau variabel di sana) karena hasilnya ReactJs tidak akan memperbarui aria / attr data dalam komponen itu. Saya telah bermain-main sepanjang hari untuk menyadari hal itu.
AlexNikonov

Jawaban:

535

Rupanya, untuk atribut tertentu, Bereaksi cukup cerdas untuk menghilangkan atribut jika nilai yang Anda berikan tidak benar. Sebagai contoh:

var InputComponent = React.createClass({
    render: function() {
        var required = true;
        var disabled = false;

        return (
            <input type="text" disabled={disabled} required={required} />
        );
    }
});

akan menghasilkan:

<input type="text" required>

Pembaruan: jika ada yang ingin tahu bagaimana / mengapa ini terjadi, Anda dapat menemukan detail dalam kode sumber ReactDOM, khususnya pada baris 30 dan 167 dari file DOMProperty.js .

juandemarco
sumber
45
Secara umum nullberarti "bertindak seperti saya tidak menentukannya sama sekali". Untuk atribut dom boolean true / false lebih disukai daripada mengulangi nama atribut / false, misalnya <input disabled>kompilasi keReact.createElement('input', {disabled: true})
Brigand
Saya setuju. Saya ulangi nama itu karena saya punya masalah di masa lalu dengan browser tertentu dan kebiasaan itu sangat mengganggu saya sehingga saya menambahkan secara manual ="required"bagian itu. Chrome sebenarnya membuat hanya atribut tanpa nilai.
juandemarco
8
readonlytidak pernah ditambahkan karena React mengharapkan atribut readOnly(dengan modal O).
Maks
8
Terima kasih! Pastikan nilainya bukan hanya string kosong atau nol, ini mungkin tidak bisa dihapus. Misalnya, Anda bisa melewati nilai seperti ini, dan itu harus memastikan itu dihapus jika mengevaluasi ke false: alt={props.alt || null}.
Jake
5
Terima kasih, @Jake. Saya telah mencoba mengatur atribut false, tetapi hanya nullmemastikan atribut itu benar-benar dihapus.
Nathan Arthur
387

Jawaban juandemarco biasanya benar, tetapi di sini ada pilihan lain.

Bangun objek sesuka Anda:

var inputProps = {
  value: 'foo',
  onChange: this.handleChange
};

if (condition)
  inputProps.disabled = true;

Jadikan menyebar, secara opsional juga meloloskan alat peraga lainnya.

<input
    value="this is overridden by inputProps"
    {...inputProps}
    onChange={overridesInputProps}
 />
Perampok
sumber
14
Ini sebenarnya sangat berguna, terutama ketika menambahkan banyak properti bersyarat (dan saya pribadi tidak tahu itu bisa dilakukan dengan cara ini).
juandemarco
1
Sangat elegan, tetapi bukankah seharusnya inputProps.disabled = true?
Joppe
sangat sederhana, saya telah membuat kode saya lebih mudah dibaca tanpa memiliki banyak kondisi.
Naveen Kumar PG
Jika ada yang peduli dengan semantik yang tepat dari "gula" ini, Anda dapat melihat pada skrip bahwa .jsx Anda diubah menjadi Anda akan melihat bahwa suatu fungsi _extendstelah ditambahkan ke dalamnya, yang akan (dalam keadaan normal) mengambil propskonstruksi dari "atribut normal" dan berlaku Object.assign(props, inputProps).
Nathan Chappell
299

Berikut adalah contoh penggunaan Bootstrap 's Buttonmelalui Bereaksi-Bootstrap (versi 0.32.4):

var condition = true;

return (
  <Button {...(condition ? {bsStyle: 'success'} : {})} />
);

Bergantung pada kondisinya, dapat {bsStyle: 'success'}atau {}akan dikembalikan. Operator spread kemudian akan menyebarkan properti dari objek yang dikembalikan ke Buttonkomponen. Dalam kasus falsy, karena tidak ada properti pada objek yang dikembalikan, tidak ada yang akan diteruskan ke komponen.


Cara alternatif berdasarkan komentar Andy Polhill :

var condition = true;

return (
  <Button bsStyle={condition ? 'success' : undefined} />
);

Satu-satunya perbedaan kecil adalah bahwa dalam contoh kedua komponen dalam <Button/>'s propsobjek akan memiliki kunci bsStyledengan nilai undefined.

Arman Yeghiazaryan
sumber
5
@Punit, Operator spread memiliki prioritas lebih rendah daripada operator kondisional, sehingga kondisinya dievaluasi terlebih dahulu, (salah satu {bsStyle: 'success'}atau {}hasil darinya), kemudian objek tersebut menyebar.
Victor Zamanian
5
Apakah yang berikut melakukan hal yang sama <Button bsStyle={ condition ? 'success': undefined } /> saya menemukan sintaks sedikit lebih mudah, melewati undefinedakan menghilangkan properti.
Andy Polhill
3
@AndyPolhill terlihat baik untuk saya dan lebih mudah untuk membaca kode, satu-satunya perbedaan kecil adalah bahwa dalam contoh kode Anda dalam komponen <Button/>'s propsobjek akan memiliki kunci bsStyledengan nilai undefined.
Arman Yeghiazaryan
@AndyPolhill alasan sintaks tampaknya lebih sulit untuk dibaca adalah karena tidak ada beberapa tanda kurung implisit yang membuat contoh terlihat asing dan sulit dimengerti. Mengedit contoh untuk menambahkan tanda kurung.
Govind Rai
1
Metode pertama bekerja dengan sempurna untuk saya, terima kasih
Liran H
86

Berikut ini sebuah alternatif.

var condition = true;

var props = {
  value: 'foo',
  ...( condition && { disabled: true } )
};

var component = <div { ...props } />;

Atau versi inline-nya

var condition = true;

var component = (
  <div
    value="foo"
    { ...( condition && { disabled: true } ) } />
);
Musim
sumber
9
Saya suka pendekatan ini, itu membuat saya keren di antara rekan kerja saya. Mengesampingkan, dari kelihatannya, alat peraga hanya disahkan sebagai pasangan kunci-nilai, betulkah itu benar?
JohnnyQ
1
Jika conditionsalah, ini akan mencoba untuk memperluas / beralih ke false, yang menurut saya tidak benar.
Lars Nyström
1
@ LarsNyström, Itu masuk akal. Operator spread hanya menerima iterables, di mana falsetidak ada. Cek saja dengan Babel. Ini bekerja dengannya ketika conditiondievaluasi menjadi false karena cara Babel mengimplementasikan operator. Meskipun solusi sepele bisa jadi ...( condition ? { disabled: true } : {} ), itu menjadi sedikit bertele-tele kemudian. Terima kasih atas masukan yang bagus ini!
Musim
+1 Pendekatan ini diperlukan jika Anda ingin keluaran data-*atau aria-*atribut secara kondisional , karena merupakan kasus khusus di BEJ, sehingga data-my-conditional-attr={ false }akan menampilkan data-my-conditional-attr="false"daripada menghilangkan atribut. facebook.github.io/react/docs/dom-elements.html
ptim
32

Inilah cara saya melakukannya.

Dengan syarat :

<Label
    {...{
      text: label,
      type,
      ...(tooltip && { tooltip }),
      isRequired: required
    }}
/>

Saya masih lebih suka menggunakan cara biasa untuk menurunkan props, karena lebih mudah dibaca (menurut saya) dalam kasus tidak memiliki persyaratan.

Tanpa syarat :

<Label text={label} type={type} tooltip={tooltip} isRequired={required} />
Tony Tai Nguyen
sumber
Bisakah Anda jelaskan bagaimana bagian ini bekerja - ...(tooltip && { tooltip }),? Itu bekerja pada komponen tetapi ketika saya mencoba menggunakan sesuatu seperti ini dalam kode saya mendapatkan kesalahan yang berarti bahwa saya mencoba untuk menyebarkan nilai yang tidak dapat diubah
diubah skwisgaar
mungkin karena falseyValue && {}akan mengembalikan false, sehingga kemungkinan Anda menyebarkan false misalnya ...(false). jauh lebih baik untuk menggunakan ekspresi penuh sehingga penyebaran terus berperilaku ...(condition ? {foo: 'bar'} : {})
lfender6445
19

Anda dapat menggunakan pintasan yang sama, yang digunakan untuk menambah / menghapus (bagian dari) komponen ( {isVisible && <SomeComponent />}).

class MyComponent extends React.Component {
  render() {
    return (
      <div someAttribute={someCondition && someValue} />
    );
  }
}
GijsjanB
sumber
3
Jika someConditionbenar tetapi someValuesalah (mis. Itu falsesendiri, atau 0, dll.), Apakah atribut masih disertakan? Ini penting jika perlu untuk secara eksplisit memasukkan nilai falsy, misalnya a 0untuk atribut koordinat, dll.
Andrew Willems
Biasanya, atribut dihilangkan, tetapi tidak dalam kasus data-*dan aria-*, lihat komentar saya di atas. Jika Anda mengutip nilainya, atau melemparkannya sebagai sebuah String, atribut tersebut akan menampilkan: eg someAttr={ `${falsyValue}` }bisa someAttr="false"
me
19

Katakanlah kita ingin menambahkan properti khusus (menggunakan aria- * atau data- *) jika kondisinya benar:

{...this.props.isTrue && {'aria-name' : 'something here'}}

Katakanlah kita ingin menambahkan properti gaya jika kondisinya benar:

{...this.props.isTrue && {style : {color: 'red'}}}
Mina Luke
sumber
10

Jika Anda menggunakan ECMAScript 6, Anda cukup menulis seperti ini.

// First, create a wrap object.
const wrap = {
    [variableName]: true
}
// Then, use it
<SomeComponent {...{wrap}} />
snyh
sumber
6

Ini akan berfungsi, karena status Anda akan berubah setelah panggilan Ajax, dan komponen induk akan di-render ulang.

render : function () {
    var item;
    if (this.state.isRequired) {
        item = <MyOwnInput attribute={'whatever'} />
    } else {
        item = <MyOwnInput />
    }
    return (
        <div>
            {item}
        </div>
    );
}
Michael Parker
sumber
3

Di Bereaksi Anda dapat membuat Komponen secara kondisional, tetapi juga atributnya, seperti alat peraga, className, id, dan banyak lagi.

Dalam Bereaksi itu praktik yang sangat baik untuk menggunakan operator ternary yang dapat membantu Anda membuat Komponen secara kondisional.

Contoh juga menunjukkan bagaimana membuat Komponen dan atribut style-nya secara kondisional.

Ini adalah contoh sederhana:

class App extends React.Component {
  state = {
    isTrue: true
  };

  render() {
    return (
      <div>
        {this.state.isTrue ? (
          <button style={{ color: this.state.isTrue ? "red" : "blue" }}>
            I am rendered if TRUE
          </button>
        ) : (
          <button>I am rendered if FALSE</button>
        )}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Juraj
sumber
Ini bisa sangat berantakan dengan banyak atribut. Saya suka varian spread yang lebih baik.
Remi Sture
Ya, Anda benar tetapi ini untuk seseorang yang perlu mendapatkan ikhtisar saya akan membuat contoh lain. Tetapi ingin menjaga hal-hal sederhana.
Juraj
0

Mempertimbangkan pos JSX Dalam Kedalaman , Anda dapat memecahkan masalah Anda dengan cara ini:

if (isRequired) {
  return (
    <MyOwnInput name="test" required='required' />
  );
}
return (
    <MyOwnInput name="test" />
);
Viktor Kireev
sumber