https://fullstackopen-2019.github.io/
Materiaali on lisensoitu Creative Commons BY-NC-SA 3.0 -lisenssillä
License: Other
https://fullstackopen-2019.github.io/
Hi there,
I think it would be a big help to have separate channels for different topics e.g Part 1 help, English help, Finnish help etc. Currently it's difficult to navigate between the comments since everything is in one channel.
Are there any plans to migrate away from Telegram to something like that supports different channel topics like Slack/Discord/Gitter?
Also mern.io is not responding at the moment..
On Part 1.c, topic passing state to child components, it is said that :
One best practice in React is to lift the state up as high as possible in the component hierarchy, preferably to the App root component.
I think this my be misleading to many newcomers to React, it implies that the best place for all state to reside in on the App root component, which is not what the reactjs docs says about. It explicit says that state should be lifted to highest common ancestor to two components that use that state.
Recommending that state preferably resides on the App root would lead to many useless re-renders of components passing down prop changes to it's children and force many components to "know" about states that don't have anything to do with them.
I think it would be better to say that state should reside on the highest common ancestor and latter when a example with a deeper component tree is shown reintroduce the concept showing a refactor to highest common ancestor. (Similar to what is done on reactjs documentation
Revise the basics of HTML by reading this tutorial from Mozilla: HTML tutorial.
Shouldn't it be “Review” instead of “Revise”?
Ensinnäkin kiitos hienosta kurssista ja terveisiä CRA-tiimiltä 👋
Kävin omaksi iloksi kurssia lävitse ja huomasin seuraavan (todella yleisen) footgunin:
Kohdassa Tilallinen komponentti käytetään setTimeout
metodia kutsumaan setState
funktiota laskurin korottamiseksi:
import React, { useState } from 'react'
import ReactDOM from 'react-dom'
const App = (props) => {
const [ counter, setCounter ] = useState(0)
setTimeout(
() => setCounter(counter + 1),
1000
)
return (
<div>{counter}</div>
)
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
Esimerkissä ei sinällään ole vikaa ja se toimii hyvin, mutta jos komponenttia muokataan hieman tosi elämän usecasen suuntaan huomataan seuraava lifecycle-ongelma:
https://codesandbox.io/s/j28p3xz229
import React, { useState } from 'react'
import ReactDOM from 'react-dom'
const Counter = (props) => {
const [counter, setCounter] = useState(0)
setTimeout(
() => setCounter(counter + 1),
100
)
return (
<div>{counter}</div>
)
}
function App() {
const [x, set ] = useState(true)
return <div onClick={() => set(false)}>
{x ? <Counter /> : null}
</div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
Klikatessa laskuria silloin tällöin konsoliin nousee seuraava virheilmoitus:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
React poisti (unmount) <Counter />
komponentin, mutta sitä vasten silti kutsuttiin setState
a koska sitä ei ollut siistitty. setTimeoutin (kuten myös varsinkin setIntervalin
) käyttö on harmittavan epätriviaalia, mutta laskurin siistiminen useEffect
-hookia käyttäen on mahdollista vaikkapa seuraavaan tyyliin:
https://codesandbox.io/s/j28p3xz229
import React, { useState, useEffect } from 'react'
import ReactDOM from 'react-dom'
const Counter = (props) => {
const [counter, setCounter] = useState(0)
useEffect(() => {
const x = setTimeout(
() => setCounter(counter + 1),
100
)
return () => clearTimeout(x)
}, [counter])
return (
<div>{counter}</div>
)
}
function App() {
const [x, set ] = useState(true)
return <div onClick={() => set(false)}>
{x ? <Counter /> : null}
</div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
useEffect
-hookia kutsutaan kun komponetti on mountattu ja siitä palautuvaa funktiota kun unmount-tapahtuu, joka korjaa ongelman. useEffect
ille pitää kuitenkin syöttää muuttujan counter
arvo arrayssä, jotta React uudelleen ajaa efektin kun arvo päivittyy.
Tuossa voisi olla hyvä sauma avata vähän Reactin lifecycleä, joka on olennainen osa (ja ehkä suurin päänvaiva) Reactia 😃 Samaa kaavaa käyttää myös Reactin omat ohjeet
As stated in the title, the npm run build:ui
command does not work in Windows 10 CMD.
Propose adding reference to a Windows friendly command. In my experience, the following command works with the directory structure:
-- course
-- -- part 2 (frontend)
-- -- part 3 (backend)
"build:ui": "rmdir build /s /q && cd ../part2 && npm run build && xcopy build ..\\part3\\build /s /e /y /i",
I have tried to keep it succinct.
In order to start part 3, I thought it necessary to clone this repository with its respective npm install && npm start
.
However, doing this returns a MongooseError which goes:
message: 'The 'uri' parameter to 'openUri()' must be a string, got "undefined". Make sure the first parameter to 'mongoose.connect()' or 'mongoose.createConnection()' is a string.', name: 'MongooseError'
What do I do? 😨
In exercise for Part 3a, we create an API with url /api/persons
but the previous Phonebook exercise in Part 2 uses url /persons
.
Could there be more instructions to explicitly change url in phonebook before continuing from part 3a to part 3b?
Hello,
I just got a little issue with the i18n of the header menu when i switch to English from the main page the content of the pages quickly loads the English version but the menu takes time to update due to my slow internet so when i click on the FAQ i get the FI version not the ENG one.
Hello.
I saw many times the NB abbreviation through the course pages and I never knew what his meaning was until I searched on Wikipedia.
Maybe I'm a bit ignorant but this is the first time I see this abbreviation.
Could it be added a slightly reminder to emphasize when a NB note is seen?
On General Info page for example.
I think the notes are very useful like all the course material.
I think useState for complex data structures is not being explained adequately. There needs to be multiple values in the state to store votes for each anecdote, but the starter code only shows a single vote and setVote. It isn't clear how to set up state as an object that can handle this.
" if you decide to store the votes of each anecdote into an array or object in the component's state, you should refer to the material to see the correct way of updating state stored in complex data structures like objects and arrays."
The emphasized phrasing here tells us there is a way to do this without storing an object or array in the state. But this not clear.
The example code in the Complex State section doesn't really help, since
"Storing all of the state in a single state object is a bad choice for this particular application; there's no apparent benefit and the resulting application is a lot more complex".
The example in the Handling Arrays section is also not really applicable to the exercise. It shows how to have an array that can accept two different values, but each value needs its own function. I'm assuming that creating a function for each anecdote would not be optimal, but that's the only solution that the readers are led to from the guide.
I think kicking the user to the React docs to figure this out defeats the purpose of having a course. Please let me know if there are any revisions to this section in progress. Thanks.
There are a couple of spelling mistakes on this page: https://fullstackopen.com/en/faq
gereatest -> greatest
cypres.io -> cypress.io
see more here -> Add "/en/" to the link
Resolved by #659
This took my a while to figure out (Googling also didn't help much) - the reasoning behind creating a note object rather than using a model constructor.
I suggest mentioning that using the Note model constructor initiates it with an _id
key, so that when attempting to update Mongo will be pissed and throw an error.
Great course by the way!
After the part
The public interface of the module is defined by setting a value to the module.exports variable. We will set the value to be the Note model. The other things defined inside of the module, like the variables mongoose and url will not be accessible or visible to users of the module.
there's no explicit closure of DB connection.
Please explain why there's no mongoose.connection.close()
any more although it's specifically highlighted that it should be done.
I'm using Chrome Version 79.0.3945.88, and I found that scrolling becomes janky and stuttering after clicking the arrow to return to the top of the page in the course contents. This scrolling behavior is only apparent in the course contents pages. When I navigate to other pages on the site ("About course", "FAQ", etc) after clicking the arrow button, scrolling is normal. Scrolling returns to normal on the course contents pages after refreshing.
With the introduction of hooks, i find it much easier to use the new "useSelector()" and "useDispatch()" methods to create redux actions and access the redux state. Since the course uses functional components and hooks over the traditional class component, I think using the new redux hooks would fall right inline with the curriculum.
For example, to access notes in the redux state:
import React from 'react'
import { useSelector } from 'react-redux'
export const NotesComponent = () => {
const notes = useSelector(state => state.notes)
return <div>{notes}</div>
}
In the section on creating event handlers it may be very useful to describe how to work with a components properties from within the event handler.
This would make the exercises much easier.
It is not safe to store sensitive data in localStorage. LocalStorage is readable by JavaScript, which in this case has been its intended purpose. However that's not how you do a secure authentication system.
Consider the following:
npm
packages. This could lead you to an attack type where a dependency can manipulate data on your webpage. This leads to compromising of all tokens for every user. [1]How to overcome this?
Use cookies. Especially httpOnly cookies with the secure flag. They've been battle-tested for decades now. The httpOnly flag tells the browser to never give JavaScript access to the cookie value. The secure flag tells the browser to never send the cookie to an unencrypted site.
"But this wont work since we're using React, right?"
Wrong. You can still serve your users a SPA site with a login page. The login page will make an XHR request to the backend API endpoint with the username and password as POST parameters. The server will respond with the user data if successful and with an error message if not.
That's it. That's how easy it is.
"Wait what happens if I reload the page?"
Well the page will reload but you are still logged in. How? Well the magic is in the session cookie. The server sent you the user data on the body, but the header information contained the cookie which your SPA JavaScript never saw. The client browser just grabbed the cookie automatically and stores it. It also sends it back to the server an all further requests. If the session dies or is not set, the backend will respond with an error asking for authentication and the client can display it in a nice, meaningful way.
Additionally, the cookie most likely has to have SameSite flag set to Lax for this to work. One could also host the SPA page from static file host such as GitHub Pages or Amazon S3 but have the backend endpoint on a subdomain and on a separate server somewhere else. For that to be secure some CORS headers would be necessary.
[1] https://www.theregister.co.uk/2018/11/26/npm_repo_bitcoin_stealer/
On part 2 of the notes project, there is an import from the services file that looks like this:
import noteService from './services/notes'
But there is no component or method in the notes file by this name.
Not sure if i'm totally missing something here, but could please explain why this is actually working?
The link titled 'currying,' redirecting to the following page is broken:
http://www.datchley.name/currying-vs-partial-application/
Not sure if it's temporary, but the entire datchley.name site appears to be down
I can't figure it out what we're supposed to do here. Based on the image of the exercise instruction, I find it confusing.
In part 4b, the section Error handling and async/await contains a test that will fail:
test('a specific note can be viewed', async () => {
const notesAtStart = await helper.notesInDb()
const noteToView = notesAtStart[0]
const resultNote = await api
.get(`/api/notes/${noteToView.id}`)
.expect(200)
.expect('Content-Type', /application\/json/)
expect(resultNote.body).toEqual(noteToView)
})
Specifically, Jest will take issue with the way the note's date is formatted:
expect(received).toEqual(expected) // deep equality
- Expected
+ Received
Object {
"content": "HTML is easy",
- "date": 2020-01-22T05:06:35.866Z,
+ "date": "2020-01-22T05:06:35.866Z",
"id": "5e27d85dc41be71f7cfd1ff6",
"important": false,
}
I'm not a Javascript wizard (hence why I'm taking this course), but it seems like Express really wants to parse the date field as a string, whereas MongoDB will return a raw Date as expected.
Modify the noteSchema's toJSON() transform to convert the date to a string when necessary:
noteSchema.set('toJSON', {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString()
returnedObject.date = returnedObject.date.toString()
delete returnedObject._id
delete returnedObject.__v
}
})
Or, maybe I'm dumb and missed something in the text. Either way wanted to bring this up.
the link to the Git instructions refers to a page in Finnish.
it is line 145 of the code:
The course exercises are submitted to GitHub, so Git must be installed and one should know how to use it. Instructions for Git can be found i.a here.
Not sure if the exercise is missing or the numbering is off but it seems like 4.14 does not exist
Mongoose doesn't run validation on default when updating objects and needs to be run with the runValidators: true
option. This should be mentioned in exercise 3.19.
In Part 4a, there are two "Exercises" section, and thus two table of contents sidebar links to exercises. The table of contents sidebar link to the second exercises does not work, because the same ID is generated for both exercise sections in the document.
A possible solution: Could the markdown-to-HTML generator take into consideration repeat Headings and append a -2
onto the end of the second exercise section ID, making it distinct?
While I was working on exercises from part 8e, I stumbled upon this error "Cannot read property 'headers' of undefined" while trying to listen to a subscription in GraphQL interface on localhost:4000. I managed to fix it like this:
const auth = req && req.headers.authorization ? req.headers.authorization : null;
For WS requests req
object is undefined
, so this code from previous parts
const auth = req.headers.authorization ? req.headers.authorization : null;
gives error
There seem to be issues with the favicon of https://fullstack-exampleapp.herokuapp.com/notes in the course's first section that could be confusing for beginners. Instead of just seeing the working requests that are described in the course module, they'll also receive an error 404.
In Exercise 1.10: unicafe step5 it says
Extract the following two components:
- Button for defining the buttons used for submitting feedback - Statistic for displaying a single statistic, e.g. the average score.
The solution of part 1, however, doesn't include the Button component and instead renders normal jsx buttons inside of the App component.
const arto = new Person('Adam Ondra', 35)
adam.greet()
transition
is defined twice in Header.scss
. I'm guessing the second one should stay since it was overwriting the first one anyway.
.header {
...
transition: top 0.2s ease-in-out;
...
transition: all 0.2s ease-in-out;
}
Use .startsWith instead of .indexOf method for filtering arrays composed of objects with details of a country because normal usage assumes the user putting in the name from the starts.
Plus, it teaches one more array method to learners.
I am using Docker and my browser is not at localhost, and I need to use Docker ip 172.17.0.2
When trying to connect to the json-server with axios, I get error in browser:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://172.17.0.2:3001/notes. (Reason: CORS request did not succeed).
This can be overridden by using the JSONP (npm install --save axios-jsonp)
And changing the App.js code:
..
import jsonpAdapter from 'axios-jsonp'
..
useEffect(() => {
axios({
url: 'http://172.17.0.2:3001/notes',
adapter: jsonpAdapter
}).then(response => {
setNotes(response.data)
})
}, [])
The header bar goes invisible when the user scrolls down, but captures pointer/touch events.
(Some of us like to read with the content right up against the top of the browser viewport 😛 )
Expected Behavior: The user would be able to click on a link right up against the top of the page if it is visible.
Observed Behavior: The user cannot click on a link that is beneath the invisible header.
Steps to Reproduce:
Possible Fix: Would it be a simple fix to make the header pass on touch/pointer events while it's in its hidden state?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.