Несколько советов, как повысить уровень счастья в React-разработке

JavaScript React.js

Еще одно резюме из ежедневной разработки: все гости, пожалуйста, садитесь, а продавцы будут разносить блюда по одному.

Первое блюдо: дважды приготовленная свинина

Цикл массива реакции в основном устанавливает уникальный ключ.Цикл массива объектов таблицы, как правило, не проблема, и данные в основном имеют идентификатор. В некоторых случаях он довольно жалкий, появляется в структуре страницы в виде формы, а массив добавляется, удаляется или модифицируется, вообще для необъектных массивов нет id, и многие быть ленивым.При зацикливании задавайте его напрямую.В качестве ключа используется подстрочный индекс массива.При добавлении,удалении и изменении будут проблемы,такие как несоответствие данных или повторный рендеринг компонентов. Существует множество решений, таких как реорганизация массива строк и других массивов объектов, присвоение каждому элементу уникального идентификатора и т. д. Есть и другой способ: рекомендуется использоватьshortidСоздайте массив уникальных ключей и используйте его с массивом данных, избавляя от необходимости реорганизации массива при отправке данных.

import React from 'react';
import shortid from 'shortid';

class Demo extends React.Component {
    constructor(props) {
		super(props);
		this.state = {
			data: ['a', 'b', 'c']
		}
		this.dataKeys = this.state.data.map(v => shortid.generate());
	}
	
    deleteOne = index => { // 删除操作
        const { data } = this.state;
        this.setState({ data: data.filter((v, i) => i !== index) });
        this.dataKyes.splice(index, 1);
    }
    
    render() {
	    return (
    	    <ul>
               {
                   data.map((v, i) => 
                    <li 
                        onClick={i => this.deleteOne(i)}  
                        key={this.dataKeys[i]}
                    >
                        {v}
                    </li>
                    )
               } 
            </ul>
	    )
	}
}
// 稍微抽取,可以封装一个通用的组件
Второе блюдо: яичница с помидорами

Отображается ли элемент, контролируется путем оценки того, существует ли значение. Как правило, тернарная операция может достичь этого эффекта. Самый простой способ - использовать метод записи короткого замыкания:

// 不错
const flag = 'something';
flag && <div></div>

// 很好
// 注意一般可能上面写法多一些,但当flag为0 的时页面上会显示0,用!!将其转为boolean避免坑,
// 代码也更规范
const flag = 'something';
!!flag && <div></div>
Третье блюдо: кисло-острые картофельные ломтики

Используя компоненты, передайте реквизиты:

const { data, type, something } = this.state;
<Demo 
    data={data}
    type={type}
    something={something}
/>

Возможно, другой способ передачи более лаконичен:

const { data, type, something } = this.state;
<Demo 
    {...{ data, id, something }}
/>
скопировать код
Четвертое блюдо: Жареные овощи

Реквизиты компонента иногда определяются много, но при вызове компонента для передачи реквизитов вы хотите передать их один за другим, вместо того, чтобы передавать объект опции за один раз, эту операцию можно упростить с помощью оператора распространения и задание на деструктуризацию:

const Demo = ({ prop1, prop2, prop3, ...restProps }) => (
    <div>
        xxxx
        { restProps.something }
    </div>
)
// 父组件使用Demo
<Demo
    prop1={xxx}
    prop2={xxx}
    something={xxx}
/>
скопировать код
Курс пятый: Закуска - Ciba

Один из способов изменить значение состояния в целом:

const { data } = this.state;
this.setState({ data: {...data, key: 1 } });

Другой способ изменить значение состояния через обратный вызов

this.setState(({ data }) => ({ data: {...data, key: 1 } }));

Достаточно хорошо:

this.setState((state, props) => {
    return { counter: state.counter + props.step };
});
Шестое блюдо: ломтики отварной свинины

Есть много способов оптимизировать производительность React, один из распространенных — определить определенные значения или свойства в функции жизненного цикла shouldComponentUpdate, чтобы контролировать, будет ли компонент перерисовываться.

Судя по обычным строкам, числам или базовым объектам, массивы по-прежнему относительно просты в обращении, а вложенные объекты или массивы доставляют больше хлопот.

Рекомендуется использовать lodash (или другую подобную библиотеку)isEqualОценка вложенных массивов или объектов (проще, чем другие методы)

shouldComponentUpdate(nextProps, nextState) {
    if (_.isEqual(nextState.columns, this.state.columns)) return false;
    return true;
}
Седьмое блюдо: кролик в сухом горшке

Существует три способа создания слоя маркеров:

  1. Обычные компоненты управляются состоянием и стилем, а всплывающий слой отображается в текущем компоненте — каждый раз, когда компонент вводится и отображение управляется в рендере, узел монтирования находится в компоненте.
// 弹层 
const Dialog = () => <div>弹层</div>
// 某组件
render() {
    return (
        this.state.showDialog && <Dialog />
    )
}

2. Создать канал через Порталы и монтировать компоненты вне корневого узла - но его все равно нужно каждый раз импортировать и вызывать в рендере

// 弹层 
class Dialog extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement('div');
  }
  componentDidMount() {
    modalRoot.appendChild(this.el);
  }
  componentWillUnmount() {
    modalRoot.removeChild(this.el);
  }

  render() {
    return ReactDOM.createPortal(
      this.props.children || <div>xxxx</div>,
      this.el,
    );
  }
}
// 某组件
render() {
    return (
        this.state.showDialog && <Dialog />
    )
}

3. Для создания эластичного слоя рекомендуется использовать ReactDom.render — монтировать внешний слой корневой ноды, что удобнее в использовании

// demo
let dialog;
class Dialog {
    show(children) {    // 显示
        this.div = document.createElement('div');
        document.body.appendChild(this.div);

        ReactDom.render(children || <div>xxxx</div>, this.div);
    }
    destroy() {     // 销毁
        ReactDom.unmountComponentAtNode(this.div);
        this.div.parentNode.removeChild(this.div);
    }
}
export default {
    show: function(children) {
        dialog = new Dialog();
        dialog.show(children);
    },
    hide: xxxxx
};
// 某组件
import Dialog from 'xxx';
alert = () => {
    Dialog.show(xxxx);
}
render() {
    return (
        <button onClick={this.alert}>点击弹层</button>
    )
}
Восьмое блюдо: жареная свинина

Render props — очень популярный сейчас метод рендеринга, который рендерит дочерние компоненты через callback-функции, а параметрами могут быть любые значения свойств родительского компонента (На официальном сайте также есть соответствующее введение) Новая версия contextApi также принимает этот режим.

Есть много сценариев, где используется этот подход:

// 权限控制组件,只需要封装一次connect,
// 通过render props向子组件传递权限
class AuthWidget extends Component {
    render() {
        return this.props.children(this.props.auth);
    }
}

const mapStateToProps = state => {
    const { auth } = state;
    return { auth: state.auth };
};
export default connect(mapStateToProps)(AuthWidget);

// 其他组件使用
<AuthWidget
    children={auth => auth.edit && <a>编辑</a>}
/>

// 使用antd的form时
const Test = ({ form, children }) => {
    return children(form);
};
const FormTest = Form.create()(Test);

class Demo extends Component {
    render() {
        return (
            <div>
                xxxxx
                <FormTest>
                    { form => {
                        this.form = form;
                        return (
                            <Form>
                                <Form.Item>
                                    {getFieldDecorator('field', xxx)(
                                        <Input placeholder="请输入链接地址" />
                                    )}
                                </Form.Item>
                            </Form>
                        )
                    }}
                </FormTest>
            </div>
        )
    }
}
Девятое блюдо: вермишель с капустой и креветочным супом

Есть много способов для дочернего компонента изменить состояние родительского компонента.Вы можете установить общую функцию в родительском компоненте, аналогичную: setParentState.При обработке через callback дочернего компонента, это может быть обработано более удобно и равномерно:

// 父组件
state = {
    data: {}
}
setParentState = obj => {
    this.setState(obj);
}
// 子组件
onClick = () => {
    this.props.setParentState({ data: xxx });
}
Десятое блюдо: Мапо тофу

Никогда не устанавливайте значение состояния напрямую: this.state.data = { a: 1 }. Это вызовет несколько проблем: 1: Компонент не будет перерисовываться 2: Значение this.state в функции shouldComponentUpdate(nextProps, nextState) было изменено и совпадает со значением nextState.

Возьмите каштан:

// wrong
const { data } = this.state;
data.a = 1;     // 等价于this.state.data.a = 1;
this.setState({ data }); // shouldComponentUpdate里面观察到 this.state 和nextState的值是相同的
// 此时函数里面性能相关的优化是无效的

// correct  需要用到当前state值的写法
this.setState(state => ({ data: {...state.data, a: 1} }))
скопировать код