Làm thế nào để tôi có điều kiện thêm các thuộc tính cho các thành phần React?


551

Có cách nào để chỉ thêm thuộc tính vào thành phần React nếu một điều kiện nhất định được đáp ứng không?

Tôi phải thêm các thuộc tính bắt buộc và readOnly để tạo thành các phần tử dựa trên lệnh gọi Ajax sau khi kết xuất, nhưng tôi không thể thấy cách giải quyết điều này vì readOnly = "false" không giống như bỏ hoàn toàn thuộc tính.

Ví dụ dưới đây sẽ giải thích những gì tôi muốn, nhưng nó sẽ không hoạt động (Lỗi phân tích: Định danh không mong đợi).

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" : ""} />
        );
    }
});

1
Có thể là một bình luận giúp ai đó, tôi đã tìm ra React 16.7 không đăng ký lại và cập nhật các thuộc tính html của thành phần nếu bạn chỉ thay đổi chúng trong một cửa hàng (từ redux) và gắn với thành phần. Điều này có nghĩa là thành phần có aria-modal=true, bạn đẩy các thay đổi (thành false) vào kho lưu trữ các thuộc tính aria / dữ liệu , nhưng không có gì khác được thay đổi (chẳng hạn như nội dung hoặc lớp hoặc các biến trong đó) vì ReactJs sẽ không cập nhật aria / dữ liệu attrs trong các thành phần đó. Tôi đã loay hoay cả ngày để nhận ra điều đó.
AlexNikonov

Câu trả lời:


535

Rõ ràng, đối với một số thuộc tính nhất định, React đủ thông minh để bỏ qua thuộc tính nếu giá trị bạn chuyển đến nó không phải là sự thật. Ví dụ:

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

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

sẽ cho kết quả:

<input type="text" required>

Cập nhật: nếu có ai tò mò về cách thức / lý do tại sao điều này xảy ra, bạn có thể tìm thấy chi tiết trong mã nguồn của ReactDOM, đặc biệt tại các dòng 30167 của tệp DOMProperty.js .


45
Nói chung nullcó nghĩa là "hành động như tôi đã không chỉ định nó ở tất cả". Đối với các thuộc tính dom boolean, true / false được ưu tiên hơn là lặp lại tên thuộc tính / false, ví dụ: <input disabled>biên dịch thànhReact.createElement('input', {disabled: true})
Brigand

Tôi đồng ý. Tôi nhắc lại tên bởi vì tôi đã gặp vấn đề trong quá khứ với một số trình duyệt nhất định và thói quen mắc kẹt với tôi đến nỗi tôi đã thêm ="required"phần thủ công . Chrome thực sự đã chỉ hiển thị thuộc tính mà không có giá trị.
juandemarco

8
readonlykhông bao giờ được thêm vì React đang mong đợi thuộc tính readOnly(có chữ O viết hoa).
Tối đa

8
Cảm ơn! Hãy chắc chắn rằng giá trị không chỉ là một chuỗi rỗng hoặc 0, những giá trị này có thể không bị xóa. Ví dụ: bạn có thể chuyển một giá trị như thế này và nó sẽ đảm bảo nó bị xóa nếu đánh giá thành false : alt={props.alt || null}.
Jake

5
Cảm ơn, @Jake. Tôi đã thử đặt thuộc tính thành false, nhưng chỉ nullchắc chắn rằng thuộc tính đã thực sự bị xóa.
Nathan Arthur

386

Câu trả lời của juandemarco thường đúng, nhưng đây là một lựa chọn khác.

Xây dựng một đối tượng như thế nào bạn thích:

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

if (condition)
  inputProps.disabled = true;

Kết xuất với lây lan, tùy ý chuyển các đạo cụ khác cũng có.

<input
    value="this is overridden by inputProps"
    {...inputProps}
    onChange={overridesInputProps}
 />

14
Điều này thực sự rất hữu ích, đặc biệt là khi thêm nhiều thuộc tính một cách có điều kiện (và cá nhân tôi không biết nó có thể được thực hiện theo cách này).
juandemarco

1
Rất thanh lịch, nhưng không nên là inputProps.disables = true?
Joppe

rất đơn giản, tôi đã làm cho mã của mình dễ đọc hơn với nhiều điều kiện.
Naveen Kumar PG

Nếu bất cứ ai quan tâm đến ngữ nghĩa chính xác của "đường" này, bạn có thể xem tập lệnh mà .jsx của bạn được dịch vào bạn sẽ thấy rằng một hàm _extendsđã được thêm vào, trong trường hợp thông thường sẽ lấy propstừ "thuộc tính bình thường" và áp dụng Object.assign(props, inputProps).
Nathan Chappell

299

Dưới đây là một ví dụ của việc sử dụng Bootstrap 's Buttonqua Phản ứng-Bootstrap (phiên bản 0.32.4):

var condition = true;

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

Tùy thuộc vào điều kiện, một {bsStyle: 'success'}hoặc {}sẽ được trả lại. Toán tử lây lan sau đó sẽ trải các thuộc tính của đối tượng được trả về Buttonthành phần. Trong trường hợp giả, vì không có thuộc tính nào tồn tại trên đối tượng được trả về, nên sẽ không có gì được truyền cho thành phần.


Một cách khác dựa trên nhận xét của Andy Polhill :

var condition = true;

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

Sự khác biệt nhỏ duy nhất là trong ví dụ thứ hai <Button/>, propsđối tượng của thành phần bên trong sẽ có một khóa bsStylecó giá trị là undefined.


5
@Punit, Nhà điều hành lây lan có độ ưu tiên thấp hơn so với các nhà điều hành có điều kiện, vì vậy tình trạng này được đánh giá đầu tiên, (một trong hai {bsStyle: 'success'}hoặc {}kết quả từ nó), sau đó đối tượng là lây lan.
Victor Zamanian

5
Những điều sau đây sẽ làm tương tự <Button bsStyle={ condition ? 'success': undefined } /> tôi thấy cú pháp dễ hơn một chút, vượt qua undefinedsẽ bỏ qua thuộc tính.
Andy Polhill

3
@AndyPolhill có vẻ tốt đối với tôi và dễ đọc mã hơn, sự khác biệt nhỏ duy nhất là trong ví dụ mã của bạn <Button/>, propsđối tượng của thành phần bên trong sẽ có một khóa bsStylecó giá trị undefined.
Arman Yeghiazaryan

@AndyPolhill lý do cú pháp có vẻ khó đọc hơn là vì nó thiếu một số dấu ngoặc đơn ẩn khiến cho ví dụ này trông xa lạ và khó hiểu hơn. Chỉnh sửa ví dụ để thêm dấu ngoặc đơn.
Govind Rai

1
Phương pháp đầu tiên hoạt động hoàn hảo với tôi, cảm ơn bạn
Liran H

86

Đây là một thay thế.

var condition = true;

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

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

Hoặc phiên bản nội tuyến của nó

var condition = true;

var component = (
  <div
    value="foo"
    { ...( condition && { disabled: true } ) } />
);

9
Tôi thích cách tiếp cận này, nó làm cho tôi mát mẻ giữa các đồng nghiệp của tôi. Đùa sang một bên, từ vẻ bề ngoài của nó, các đạo cụ chỉ được thông qua như một cặp khóa-giá trị, điều đó có đúng không?
JohnnyQ

1
Nếu conditionlà sai, điều này sẽ cố gắng mở rộng / lặp lại sai, điều mà tôi không nghĩ là đúng.
Lars Nyström

1
@ LarsNyström, Điều đó có ý nghĩa. Toán tử lây lan chỉ chấp nhận các lần lặp, trong đó falsekhông phải là một. Chỉ cần kiểm tra với Babel. Điều này hoạt động với nó khi conditionđánh giá là sai vì cách Babel thực hiện toán tử. Mặc dù một cách giải quyết tầm thường có thể ...( condition ? { disabled: true } : {} ), nhưng sau đó nó trở nên hơi dài dòng. Cảm ơn cho đầu vào tốt đẹp này!
Mùa

+1 Cách tiếp cận này là bắt buộc nếu bạn muốn đầu ra có điều kiện data-*hoặc aria-*thuộc tính, vì chúng là trường hợp đặc biệt trong JSX, do đó data-my-conditional-attr={ false }sẽ xuất ra data-my-conditional-attr="false"thay vì bỏ qua thuộc tính. facebook.github.io/react/docs/dom-elements.html
ptim

32

Đây là một cách tôi làm điều đó.

Với một điều kiện :

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

Tôi vẫn thích sử dụng cách thông thường để chuyển các đạo cụ xuống, bởi vì nó dễ đọc hơn (theo ý kiến ​​của tôi) trong trường hợp không có bất kỳ điều kiện nào.

Nếu không có điều kiện :

<Label text={label} type={type} tooltip={tooltip} isRequired={required} />

Bạn có thể giải thích làm thế nào phần này hoạt động - ...(tooltip && { tooltip }),? Nó không hoạt động trên thành phần nhưng khi tôi cố gắng sử dụng một cái gì đó như thế này trong mã tôi gặp một lỗi có nghĩa là tôi cố gắng truyền bá giá trị không thể lặp lại
skwisgaar

có lẽ bởi vì falseyValue && {}sẽ trả về false, vì vậy có khả năng bạn đang lan truyền trên false, vd ...(false). tốt hơn nhiều để sử dụng biểu thức đầy đủ để sự lây lan tiếp tục hành xử ...(condition ? {foo: 'bar'} : {})
lfender6445

19

Bạn có thể sử dụng cùng một phím tắt, được sử dụng để thêm / xóa (các phần của) thành phần ( {isVisible && <SomeComponent />}).

class MyComponent extends React.Component {
  render() {
    return (
      <div someAttribute={someCondition && someValue} />
    );
  }
}

3
Nếu someConditionlà đúng nhưng someValuelà giả mạo (ví dụ: falsechính nó, hoặc 0, v.v.), thuộc tính vẫn được đưa vào? Điều này rất quan trọng nếu cần bao gồm một cách rõ ràng giá trị giả, ví dụ: 0đối với thuộc tính tọa độ, v.v.
Andrew Willems

Thông thường, thuộc tính được bỏ qua, nhưng không phải trong trường hợp data-*aria-*, xem nhận xét của tôi ở trên. Nếu bạn trích dẫn giá trị hoặc chuyển nó thành Chuỗi, thuộc tính sẽ hiển thị: ví dụ: someAttr={ `${falsyValue}` }có thể hiển thịsomeAttr="false"
ptim

19

Giả sử chúng ta muốn thêm một thuộc tính tùy chỉnh (sử dụng aria- * hoặc data- *) nếu một điều kiện là đúng:

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

Giả sử chúng ta muốn thêm thuộc tính kiểu nếu điều kiện là đúng:

{...this.props.isTrue && {style : {color: 'red'}}}

10

Nếu bạn sử dụng ECMAScript 6, bạn có thể chỉ cần viết như thế này.

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

6

Điều này sẽ hoạt động, vì trạng thái của bạn sẽ thay đổi sau lệnh gọi Ajax và thành phần cha mẹ sẽ kết xuất lại.

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

3

Trong React, bạn có thể hiển thị một cách có điều kiện các Thành phần, nhưng cả các thuộc tính của chúng, như đạo cụ, className, id, v.v.

Trong React, cách tốt nhất là sử dụng toán tử ternary có thể giúp bạn hiển thị các thành phần một cách có điều kiện.

Một ví dụ cũng cho thấy cách hiển thị có điều kiện Thành phần và thuộc tính kiểu của nó.

Đây là một ví dụ đơn giản:

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>


Điều này có thể trở nên thực sự lộn xộn với rất nhiều thuộc tính. Tôi thích các biến thể lây lan tốt hơn.
Remi Sture

Có Bạn đúng nhưng điều này là dành cho ai đó cần có cái nhìn tổng quan, tôi sẽ làm một ví dụ khác. Nhưng muốn giữ mọi thứ đơn giản.
Juraj

0

Xem xét bài viết JSX In Depth , bạn có thể giải quyết vấn đề của mình theo cách này:

if (isRequired) {
  return (
    <MyOwnInput name="test" required='required' />
  );
}
return (
    <MyOwnInput name="test" />
);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.