javascript - ماهو - react ترجمة




لماذا لا يجب على الدعائم JSX استخدام وظائف السهم أو الربط؟ (4)

أشغل الوبر مع تطبيق React الخاص بي ، وأتلقى هذا الخطأ:

error    JSX props should not use arrow functions        react/jsx-no-bind

وهذا هو المكان الذي أدير فيه وظيفة السهم (داخل onClick ):

{this.state.photos.map(tile => (
  <span key={tile.img}>
    <Checkbox
      defaultChecked={tile.checked}
      onCheck={() => this.selectPicture(tile)}
      style={{position: 'absolute', zIndex: 99, padding: 5, backgroundColor: 'rgba(255, 255, 255, 0.72)'}}
    />
    <GridTile
      title={tile.title}
      subtitle={<span>by <b>{tile.author}</b></span>}
      actionIcon={<IconButton onClick={() => this.handleDelete(tile)}><Delete color="white"/></IconButton>}
    >
      <img onClick={() => this.handleOpen(tile.img)} src={tile.img} style={{cursor: 'pointer'}}/>
    </GridTile>
  </span>
))}

هل هذه ممارسة سيئة يجب تجنبها؟ وما هي أفضل طريقة للقيام بذلك؟


استخدام وظائف مضمنة مثل هذا جيد تماما. حكم الوبر قديم.

هذه القاعدة هي من وقت كانت فيه وظائف السهم غير شائعة واستخدم الناس .bind (هذا) ، والتي كانت بطيئة. تم إصلاح مشكلة الأداء في Chrome 49.

لا تنتبه إلى عدم قيامك بتمرير الدالات المضمّنة كدعائم إلى مكون فرعي.

كتب ريان فلورنس ، مؤلف كتاب React Router ، مقالة رائعة عن هذا:

https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578


لتجنب إنشاء وظائف جديدة بنفس الوسيطات ، يمكنك ملاحظة نتيجة ربط الوظيفة ، فيما يلي أداة مساعدة بسيطة تسمى memobind للقيام بذلك: https://github.com/supnate/memobind


يمكنك استخدام وظائف الأسهم باستخدام مكتبة react-cached-handler ، لا داعي للقلق بشأن إعادة عرض الأداء:

ملاحظة: داخليًا ، تقوم بتخزين وظائف السهم حسب المفتاح المحدد ، ولا داعي للقلق بشأن إعادة العرض!

render() {

  return <div>
  {
        this.props.photos.map(photo=>
          <Photo key={photo.url}
            onClick={this.handler(photo.url, (url) => { 
                 console.log(url) })}
          />)
   }
 </div>

}

ميزات أخرى:

  • معالجات المسماة
  • التعامل مع الأحداث حسب وظائف السهم
  • الوصول إلى المفتاح ، الوسائط المخصصة والحدث الأصلي
  • مكون تقديم الأداء
  • سياق مخصص للمعالجات

لماذا لا يجب عليك استخدام وظائف السهم المضمنة في الدعائم JSX

يعد استخدام وظائف السهم أو الربط في JSX ممارسة سيئة تؤذي الأداء ، لأن الوظيفة يتم إنشاؤها في كل عرض.

  1. عندما يتم إنشاء وظيفة ، فإن الوظيفة السابقة هي جمع القمامة. قد يؤدي إنشاء العديد من العناصر إلى إنشاء jank في الرسوم المتحركة.

  2. سيؤدي استخدام دالة سهم مضمّنة إلى استخدام PureComponent s والمكونات التي تستخدم shallowCompare في طريقة shouldComponentUpdate لإعادة العرض على أي حال. نظرًا لإعادة إنشاء دالة السهم prop في كل مرة ، ستقوم المقارنة الضحلة بتعريفها كتغيير في prop ، وسيظهر المكون.

كما ترون في المثالين التاليين - عندما نستخدم وظيفة السهم المضمن ، يتم تقديم مكون <Button> كل مرة (تعرض وحدة التحكم نص "زر التجسيد").

مثال 1 - PureComponent بدون معالج مضمّن

class Button extends React.PureComponent {
  render() {
    const { onClick } = this.props;
    
    console.log('render button');
    
    return (
      <button onClick={ onClick }>Click</button>
    );
  }
}

class Parent extends React.Component {
  state = {
    counter: 0
  }
  
  onClick = () => this.setState((prevState) => ({
    counter: prevState.counter + 1
  }));
  
  render() {
    const { counter } = this.state;
    
    return (
      <div>
        <Button onClick={ this.onClick } />
        <div>{ counter }</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
<div id="root"></div>

مثال 2 - PureComponent مع معالج مضمن

class Button extends React.PureComponent {
  render() {
    const { onClick } = this.props;
    
    console.log('render button');
    
    return (
      <button onClick={ onClick }>Click</button>
    );
  }
}

class Parent extends React.Component {
  state = {
    counter: 0
  }
  
  render() {
    const { counter } = this.state;
    
    return (
      <div>
        <Button onClick={ () => this.setState((prevState) => ({
          counter: prevState.counter + 1
        })) } />
        <div>{ counter }</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
<div id="root"></div>

ربط الطرق this دون تضمين وظائف السهم

  1. ربط الطريقة يدويًا في المنشئ:

    class Button extends React.Component {
      constructor(props, context) {
        super(props, context);
    
        this.cb = this.cb.bind(this);
      }
    
      cb() {
    
      }
    
      render() {
        return (
          <button onClick={ this.cb }>Click</button>
        );
      }
    }
  2. ربط طريقة باستخدام proposal-class-fields مع وظيفة السهم. نظرًا لأن هذا هو اقتراح المرحلة 3 ، ستحتاج إلى إضافة الإعداد المسبق للمرحلة 3 أو تحويل خصائص الفئة إلى تكوين بابل الخاص بك.

    class Button extends React.Component {
      cb = () => { // the class property is initialized with an arrow function that binds this to the class
    
      }
    
      render() {
        return (
          <button onClick={ this.cb }>Click</button>
        );
      }
    }

مكونات وظيفة مع عمليات الاسترجاعات الداخلية

عندما ننشئ وظيفة داخلية (معالج حدث على سبيل المثال) داخل مكون وظيفة ، سيتم إعادة إنشاء الوظيفة في كل مرة يتم فيها تقديم المكون. إذا تم تمرير الوظيفة كدعائم (أو عبر السياق) إلى مكون Button ( Button في هذه الحالة) ، فسيظهر ذلك الطفل أيضًا.

مثال 1 - مكون الوظيفة مع رد اتصال داخلي:

const { memo, useState } = React;

const Button = memo(({ onClick }) => console.log('render button') || (
  <button onClick={onClick}>Click</button>
));

const Parent = () => {
  const [counter, setCounter] = useState(0);
  
  const increment = () => setCounter(counter => counter + 1); // the function is recreated all the time
  
  return (
    <div>
      <Button onClick={increment} />
      
      <div>{counter}</div>
    </div>
  );
}

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

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

لحل هذه المشكلة ، يمكننا التفاف رد الاتصال باستخدام ربط useCallback() وتعيين التبعيات إلى صفيف فارغ.

ملاحظة: تقبل الدالة useState إنشاؤها وظيفة محدث توفر الحالة الحالية. وبهذه الطريقة ، لا نحتاج إلى تعيين الحالة الحالية على تبعية useCallback .

مثال 2 - مكون الوظيفة مع رد اتصال داخلي ملفوف باستخدام useCallback:

const { memo, useState, useCallback } = React;

const Button = memo(({ onClick }) => console.log('render button') || (
  <button onClick={onClick}>Click</button>
));

const Parent = () => {
  const [counter, setCounter] = useState(0);
  
  const increment = useCallback(() => setCounter(counter => counter + 1), []);
  
  return (
    <div>
      <Button onClick={increment} />
      
      <div>{counter}</div>
    </div>
  );
}

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

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





arrow-functions