-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test task #2
base: master
Are you sure you want to change the base?
Test task #2
Conversation
Activity block is now external component; Small changes in logycs and design; Added comment to filters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
React.Children.only expected to receive a single React element child.
▼ 26 stack frames were expanded.
invariant
node_modules/react/cjs/react.development.js:105
onlyChild [as only]
node_modules/react/cjs/react.development.js:1298
Router.render
node_modules/react-router/es/Router.js:118
finishClassComponent
node_modules/react-dom/cjs/react-dom.development.js:15128
updateClassComponent
node_modules/react-dom/cjs/react-dom.development.js:15083
beginWork
node_modules/react-dom/cjs/react-dom.development.js:15967
performUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js:19093
workLoop
node_modules/react-dom/cjs/react-dom.development.js:19134
HTMLUnknownElement.callCallback
node_modules/react-dom/cjs/react-dom.development.js:147
invokeGuardedCallbackDev
node_modules/react-dom/cjs/react-dom.development.js:196
invokeGuardedCallback
node_modules/react-dom/cjs/react-dom.development.js:250
replayUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js:18341
renderRoot
node_modules/react-dom/cjs/react-dom.development.js:19252
performWorkOnRoot
node_modules/react-dom/cjs/react-dom.development.js:20156
performWork
node_modules/react-dom/cjs/react-dom.development.js:20066
performSyncWork
node_modules/react-dom/cjs/react-dom.development.js:20040
requestWork
node_modules/react-dom/cjs/react-dom.development.js:19895
scheduleWork
node_modules/react-dom/cjs/react-dom.development.js:19702
scheduleRootUpdate
node_modules/react-dom/cjs/react-dom.development.js:20406
updateContainerAtExpirationTime
node_modules/react-dom/cjs/react-dom.development.js:20432
updateContainer
node_modules/react-dom/cjs/react-dom.development.js:20500
ReactRoot.push../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render
node_modules/react-dom/cjs/react-dom.development.js:20813
(anonymous function)
node_modules/react-dom/cjs/react-dom.development.js:20967
unbatchedUpdates
node_modules/react-dom/cjs/react-dom.development.js:20283
legacyRenderSubtreeIntoContainer
node_modules/react-dom/cjs/react-dom.development.js:20963
render
node_modules/react-dom/cjs/react-dom.development.js:21030
▲ 26 stack frames were expanded.
Module../src/index.js
src/index.js:5
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
> 5 | ReactDOM.render(<App />, document.getElementById('root'));
View compiled
__webpack_require__
/home/orehov/Downloads/frontend-test-task/webpack/bootstrap:782
779 | };
780 |
781 | // Execute the module function
> 782 | modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
| ^ 783 |
784 | // Flag the module as loaded
785 | module.l = true;
View compiled
fn
/home/orehov/Downloads/frontend-test-task/webpack/bootstrap:150
147 | );
148 | hotCurrentParents = [];
149 | }
> 150 | return __webpack_require__(request);
| ^ 151 | };
152 | var ObjectFactory = function ObjectFactory(name) {
153 | return {
View compiled
0
http://localhost:3000/static/js/main.chunk.js:977:18
__webpack_require__
/home/orehov/Downloads/frontend-test-task/webpack/bootstrap:782
779 | };
780 |
781 | // Execute the module function
> 782 | modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
| ^ 783 |
784 | // Flag the module as loaded
785 | module.l = true;
View compiled
checkDeferredModules
/home/orehov/Downloads/frontend-test-task/webpack/bootstrap:45
42 | }
43 | if(fulfilled) {
44 | deferredModules.splice(i--, 1);
> 45 | result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
| ^ 46 | }
47 | }
48 | return result;
View compiled
Array.webpackJsonpCallback [as push]
/home/orehov/Downloads/frontend-test-task/webpack/bootstrap:32
29 | deferredModules.push.apply(deferredModules, executeModules || []);
30 |
31 | // run deferred modules when all chunks ready
> 32 | return checkDeferredModules();
| ^ 33 | };
34 | function checkDeferredModules() {
35 | var result;
View compiled
(anonymous function)
http://localhost:3000/static/js/main.chunk.js:1:57
Исправил. Был неверный import |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
С точки зрения пользователя есть два замечания по работе приложения:
- поля ввода
- если стереть значения, поля не подсвечиваются красным и не блокируется кнопка "Filter"
- если в первое поле попытаться ввести
a
, перейти во второе поле и нажатьb
, то в первом поле появитсяa
- модальное окно
- в тексте говорится "You found 5 activities", но фактически пользователь увидел только 4 активности
- мобильный режим
- в интерфейсе "Filters" элементы расположены неэргономично
<button className='btn btn-small' onClick={modalClose}>Cancel</button> | ||
</div> | ||
<div className="col-1-of-2"> | ||
<Link to="/filter/" className='btn btn-small'>Try!</Link> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Можно обойтись без глобальных CSS-классов, воспользовавшись свойством as
у styled-components: https://www.styled-components.com/docs/basics#extending-styles (второй пример).
В случае с Button
и Link
можно сделать так:
const Button = styled.button`
/* ...styles... */
`;
const SmallButton = styled(Button)`
/* ...more styles... */
`;
<SmallButton>Cancel</SmallButton>
<SmallButton as={Link} to="/filter/">Try!</SmallButton>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Окей, учту на будущее.
} | ||
|
||
export default GlobalStyle; | ||
export { Button, Headline, Container, ContainerInnerWrap, ActivityWrap, Strong, ActivityContent }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
В идеале каждый модуль должен отвечать за и экспортировать что-то одно. Этот модуль можно разделить как минимум на три: GlobalStyle.js
, StyledComponents.js
, и ActivityContent.js
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Учту
src/components/commonData.js
Outdated
const Price = styled.span` | ||
font-size: 24px; | ||
` | ||
const ActivityContent = (props) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Стоит активнее использовать деструктуризацию, особенно в сигнатурах функций. props
не говорит ни о чём, а взглянув на const ActivityContent = ({filter, data}) => {
сразу становится понятно что в компонент нужно передать.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Исправил
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data
тоже было бы лучше деструктурировать:
const ActivityContent = ({filter, data}) => {
const {
activity,
key,
type
/* ... */
} = data;
return /* ... */;
};
Опять же для повышения самодокументированности кода.
src/components/commonData.js
Outdated
</Price> | ||
</PriceWrap> | ||
</div> | ||
<div className={Object.keys(props.data).length === 1 ? null : 'display-none'}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Повторная проверка условия Object.keys(props.data).length === 1
. Возможно было бы лучше воспользоваться вот этой техникой: https://reactjs.org/docs/conditional-rendering.html#inline-if-else-with-conditional-operator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Исправил
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Я имел в виду вместо
<div className={isError ? 'display-none' : ''}>
<Success />
</div>
<div className={isError ? '' : 'display-none'}>
<Error />
</div>
сделать
{
isError
? <Error />
: <Success />
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Исправил
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Только теперь div
-контейнеры в Success
и Error
(которые выполняют проверку на data.error
) вообще не нужны, так как эта проверка выполняется уровнем выше, в ActivityWrap
.
src/components/Activities.js
Outdated
` | ||
function Activity() { | ||
const [data, setData] = useState({}); | ||
let [clickCount, setClickCount] = useState(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Почему let
, а не const
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Возможно копипаст... Исправил.
<ContainerInnerWrap> | ||
<Headline>WhattodoApp</Headline> | ||
<PreambulaText>{Object.keys(data).length === 0 ? `Don't know what to do? We'll help you! Just click the button and you'll see the possible variant for your vocation...` : `Don't like that? Click... ;-)`}</PreambulaText> | ||
<Button onClick={getRandomActivity} style={{ marginBottom: '20px' }}>Random</Button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Для стилизации лучше использовать какой-то один способ. Если это styled-components, то все стили должны объявляться с помощью styled-components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ОК, учту. Но как быть в том случае, если в одном месте одному элементу нужно задать отступ? Делать новый компонент по аналогии с этим?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Да.
let url = 'http://www.boredapi.com/api/activity'; | ||
|
||
if (filterType === 'priceRange') { | ||
url = `${url}?minprice=${firstValue}&maxprice=${secondValue}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Лучше использовать готовый инструмент для работы с query string, например https://www.npmjs.com/package/qs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Окей, учту.
Теперь если в первое поле попытаться ввести |
Если честно, с этим не знаю, что делать с этим... |
Может быть в данном случае бОльшую часть валидации вообще стоит переложить на плечи браузера? <input type="number" min="1" required> |
Anton Romankov