Почему `Export Default Const` недействителен?

352

Я вижу, что следующее хорошо:

const Tab = connect( mapState, mapDispatch )( Tabs );
export default Tab;

Однако это неверно:

export default const Tab = connect( mapState, mapDispatch )( Tabs );

Все же это хорошо

export default Tab = connect( mapState, mapDispatch )( Tabs );

Можно ли это объяснить, пожалуйста, почему constнедействительно с export default? Является ли это ненужным дополнением и чем-либо, объявленным как export defaultпредполагаемое constили таким?

Kayote
источник
1
export default Tab = connect( mapState, mapDispatch )( Tabs );должно быть export default connect( mapState, mapDispatch )( Tabs );. Вы экспортируете результат вызова функции, а не переменную Tab.
ThaJay
2
Const или let требуется (и уместен) в экспортирующем модуле, но не имеет значения в импортирующем модуле, где импортируемый идентификатор всегда доступен только для чтения (не может быть назначен). Это по-прежнему не объясняет, почему синтаксис «экспорта по умолчанию» отличается от «экспорта по умолчанию».
Денис Хоу

Ответы:

305

constэто как let, это LexicalDeclaration ( ВыраженияПрисваивания, декларация ) используется для определения идентификатора в вашем блоке.

Вы пытаетесь смешать это с defaultключевым словом, которое ожидает, что HoistableDeclaration, ClassDeclaration или AssignmentExpression последуют за ним.

Следовательно, это ошибка синтаксиса .


Если вы хотите constчто-то, вы должны предоставить идентификатор, а не использовать default.

exportсам по себе принимает VariableStatement или декларацию справа от себя.


AFAIK экспорт сам по себе не должен ничего добавлять к вашей текущей области.


Следующее хорошоexport default Tab;

Tabстановится выражением AssignmentExpression, так как ему присваивается имя по умолчанию ?

export default Tab = connect( mapState, mapDispatch )( Tabs ); Это хорошо

Вот Tab = connect( mapState, mapDispatch )( Tabs );выражение AssignmentExpression .

Пол С.
источник
27
Ответ в том, как это стало ошибкой. Вопрос еще почему? Единственная причина, по которой он предотвращает злоупотребление const таким образом: экспорт по умолчанию const a = 1, b = 3, c = 4;
Сергей Орлов
7
"AFAIK the export in itself should not add anything to your current scope"Это не так точно, потому что export const a = 1добавляет aк вашему текущему контексту. И даже export defaultв случае с классами, потому что export default class MyClass {}добавляет MyClassк вашему текущему контексту также.
Эрнесто
4
@SergeyOrlov согласен, что это объясняет, как это приводит к ошибке, но проливает немного света на то, почему это необходимо. Хотя я не уверен, что это единственная причина, вы, вероятно, должны опубликовать это как отдельный ответ, а не комментарий к этому.
Херик
Если я сделаю следующее: let a; export default a;а затем обновлю переменную a, если она уже была импортирована в другой модуль, почему переменная экспорта по умолчанию не обновляется?
К - Токсичность в СО растет.
Насколько я понимаю, вы можете написать, const foo = function bar() {}а также const Foo = class Bar {}, но не так const foo = const bar = 1. То же самое export default, это так же, как const foo =.
Зетавг
47

Вы также можете сделать что-то вроде этого, если вы хотите экспортировать по умолчанию const / let вместо

const MyComponent = ({ attr1, attr2 }) => (<p>Now Export On other Line</p>);
export default MyComponent

Вы можете сделать что-то подобное, что мне не нравится лично.

let MyComponent;
export default MyComponent = ({ }) => (<p>Now Export On SameLine</p>);
Адель Имран
источник
19

Если имя компонента объясняется в имени файла MyComponent.js, просто не называйте компонент, сохраняя код тонким.

import React from 'react'

export default (props) =>
    <div id='static-page-template'>
        {props.children}
    </div>

Обновление : так как это помечает это как неизвестное в трассировке стека, это не рекомендуется

Кевин Даниковский
источник
14
У вас не было проблем с трассировкой стека? Для меня это вызывает отображение Unknownвезде, где экспорт по умолчанию безымянный
Джурош
2
Несмотря на то, что это работает, без сомнения, это то, что каждый разработчик, не имеющий отношения к разработке игрушек, должен стараться избегать любой ценой.
li x
1
@lix Я не мог понять, почему следует избегать использования этого синтаксиса. Не могли бы вы объяснить или поделиться ссылкой? Спасибо.
Суд
3
@sudip Создание компонента без имени не подходит для модели реагирующего компонента и рендеринга.
li x
1
Тем не менее, выглядит чистым, также Дан Абрамов предлагает использовать правильные имена функций / констант в объявлении компонента: twitter.com/dan_abramov/status/1255229440860262400 ;) "- будет отображаться как Anonymous в трассировке стека - будет отображаться как Unknown в DevTools - не будет проверяться специфичными для React правилами lint - не будет работать с некоторыми функциями, такими как быстрое обновление "
Золтан
9

Ответ Павла тот, который вы ищете. Однако, с практической точки зрения, я думаю, что вас может заинтересовать шаблон, который я использовал в своих собственных приложениях React + Redux.

Вот упрощенный пример одного из моих маршрутов, показывающий, как вы можете определить свой компонент и экспортировать его по умолчанию с помощью одного оператора:

import React from 'react';
import { connect } from 'react-redux';

@connect((state, props) => ({
    appVersion: state.appVersion
    // other scene props, calculated from app state & route props
}))
export default class SceneName extends React.Component { /* ... */ }

(Примечание: я использую термин «сцена» для компонента верхнего уровня любого маршрута).

Я надеюсь, что это полезно. Я думаю, что это выглядит намного чище, чем обычныеconnect( mapState, mapDispatch )( BareComponent )

Том
источник
Жаль, что декораторы не могут быть использованы для функционального компонента
Эрик Ким
@EricKim Bummer. Но стоит иметь в виду, что спецификация декоратора еще не окончательная. Может быть, функциональные компоненты не могут быть оформлены с использованием «устаревшего» декоратора, но я не знаю, связано ли это с ограничением устаревшего дизайна или с тем, что реализация устаревших декораторов не завершена или содержит ошибки. FWIW: @connectединственный декоратор, который я использую, я использую его только с компонентами, которые подключены к хранилищу с избыточностью, почти каждый из них является «маршрутом», и почти каждый маршрут должен иметь состояние (и, следовательно, не может быть чистой функцией) ,
Том
8

Ответ Пола - лучший. Чтобы расширить больше,

Для каждого файла может быть только один экспорт по умолчанию. Принимая во внимание, что может быть больше чем один постоянный экспорт. Переменная по умолчанию может быть импортирована с любым именем, тогда как переменная const может быть импортирована с ее конкретным именем.

var message2 = 'Я экспортирован';

экспортировать сообщение по умолчанию2;

экспортировать константное сообщение = 'Я также экспортирован'

Что касается импорта, нам нужно импортировать его так:

import {message} из './test';

или

импортировать сообщение из «./test»;

При первом импорте импортируется переменная const, тогда как со вторым импортируется переменная по умолчанию.

Имбирное пиво
источник
0

default в основном const someVariableName

Вам не нужен именованный идентификатор, потому что это экспорт по умолчанию для файла, и вы можете называть его как хотите, когда импортируете его, поэтому defaultпросто уплотняете присвоение переменной в одно ключевое слово.

Мани Гэндхэм
источник
-3

Для меня это всего лишь одна из многих специфических особенностей (акцент на idio (t)) машинописи, которая заставляет людей вырывать волосы и проклинать разработчиков. Возможно, они могли бы работать над более понятными сообщениями об ошибках.

Большая собака
источник