Skip to content

Commit

Permalink
Remove classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Augustin Le Fèvre committed Jun 30, 2019
1 parent cc1ac06 commit 0579f1d
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 317 deletions.
25 changes: 16 additions & 9 deletions mainReactCourse.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,27 @@ Example
Practice -> intro

Component API
defaultProps can be found on functional components
propTypes can be found on functional components
default props
propTypes
children it's just a prop
this.setState
- how it works => updates the state and triggers a rerender of the component
- It's about render, not used in render, does not belong in the state
- what if is the component is unmounted ? State is lost
- How to listen to prop changes? See lifecycle
lifecycle => parent's state is kept => lift the state up
hooks
useState
- how it works => updates the state and triggers a rerender of the component
- It's about render, not used in render, does not belong in the state
- what if is the component is unmounted ? State is lost
- parent's state is kept => lift the state up
useReducer
- more powerful than useState. Use whatever you want, it doesn't really matter
- useState is implemented with useReducer
- each useState trigger a rerender, so it might be better to use a useReducer when there
are several things related in the state
useEffect
- Doing side-effects -> Anything that is not purely related to rendering


Reconciliation
The great thing with React is that your app is entirely rerendered all the time. You app is a tree (use whiteboard).
When you rerender you app (or a section of the tree, with a local setState for instance)
When you rerender you app (or a section of the tree, with a local useState for instance)
React tries to see if an element can simply be updated (or ignored).
For instance, if there was a div and a component in it, now a p and the same component, the component is recreated from scratch
Same thing with keys in list.
69 changes: 51 additions & 18 deletions presentations/deck.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,32 @@ But how do we make things pretty?
---
## React API

---
## React Classes
An older way of writing components, without hooks
```jsx
import * as React from 'react';

class Form extends React.Component {
state = {
isValid: false,
data: [],
};
componentDidMount() {
this.setState(() => {
isValid: validateForm(this.props.data);
})
}
render() {
return (
<form>
{/* ... */}
</form>
)
}
}
```

---
## Reconciliation
Do React rerenders everything all the time?
Expand All @@ -104,19 +130,22 @@ In React, the common way to use form elements is to control them.
---
## Controlled component
```jsx
class Name extends React.Component {
state = {value: ''};
handleChange = (event) => {
this.setState({value: event.target.value});
}
render() {
return <input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>;
}
}
const Name = () => {
const [value, setValue] = React.useState('');

const handleChange = (event) => {
setValue(event.target.value);
};

return (
<input
type="text"
value={value}
onChange={handleChange}
/>
);

}
```

---
Expand All @@ -140,13 +169,17 @@ A way to pass data from an upper to a lower one, without having to do it through
---
## Context
```jsx
const {Provider, Consumer} = React.createContext(defaultValue);
const Context = React.createContext(defaultValue);

const Parent = () => {
return <Context.Provider value={/* some value */}>{...}</Context.Provider>;
};

<Provider value={/* some value */}>{...}</Provider>
const Comp = () => {
const value = React.useContext(Context);
return <div>{value}</div>;
};

<Consumer>
{value => /* render something based on the context value */}
</Consumer>
```

---
Expand Down
56 changes: 23 additions & 33 deletions src/corrections/day1Correction/app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import React, {Component} from 'react';
import React from 'react';
import ReactDOM from 'react-dom';

import keywords from './helpers/keywords';
Expand All @@ -9,40 +9,30 @@ import hasContactKeywords from './helpers/hasContactKeywords';

import contacts from '../../practice/day1/mockData';

class App extends Component {
static propTypes = {
contacts: PropTypes.array.isRequired,
};

state = {
selectedKeyword: null,
};
const App = ({contacts}) => {
const [selectedKeyword, setSelectedKeyword] = React.useState(null);

selectKeyword = keyword => {
this.setState((prevState, props) => ({
selectedKeyword: prevState.selectedKeyword === keyword ? null : keyword,
}));
const filteredContacts = contacts.filter(contact =>
hasContactKeywords(contact, selectedKeyword)
);
const selectKeyword = keyword => {
setSelectedKeyword(selectedKeyword === keyword ? null : keyword);
};

render() {
const {contacts} = this.props;

const filteredContacts = contacts.filter(contact =>
hasContactKeywords(contact, this.state.selectedKeyword)
);

return (
<div>
<h1>My contacts</h1>
<Filters
keywords={keywords}
selectedKeyword={this.state.selectedKeyword}
selectKeyword={this.selectKeyword}
/>
<ContactList list={filteredContacts} />
</div>
);
}
}
return (
<div>
<h1>My contacts</h1>
<Filters
keywords={keywords}
selectedKeyword={selectedKeyword}
selectKeyword={selectKeyword}
/>
<ContactList list={filteredContacts} />
</div>
);
};
App.propTypes = {
contacts: PropTypes.array.isRequired,
};

ReactDOM.render(<App contacts={contacts} />, document.getElementById('root'));
58 changes: 25 additions & 33 deletions src/corrections/day1Correction/contact.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import React, {Component} from 'react';
import React from 'react';

import './contact.css';

Expand All @@ -20,39 +20,31 @@ const contactPropTypes = {
}).isRequired,
};

class Contact extends Component {
state = {
twitterBio: null,
};

componentDidMount() {
const {contact} = this.props;

if (contact.twitterHandle)
fetchTwitterBio(contact.id).then(({bio}) => {
this.setState({twitterBio: bio});
});
}

render() {
const {contact} = this.props;

return (
<div className="contact">
<div className="contact__header">
<div className="contact__name">{getContactDisplayName(contact)}</div>
{contact.twitterHandle && <TwitterHandle handle={contact.twitterHandle} />}
</div>
<InlineList elements={contact.keywords}>
{(element, index) => <Keyword keyword={element} key={index} />}
</InlineList>
{this.state.twitterBio && (
<div className="contact__bio">{this.state.twitterBio}</div>
)}
const Contact = ({contact}) => {
const [twitterBio, setTwitterBio] = React.useState(null);
React.useEffect(
() => {
if (contact.twitterHandle)
fetchTwitterBio(contact.id).then(({bio}) => {
setTwitterBio(bio);
});
},
[contact]
);

return (
<div className="contact">
<div className="contact__header">
<div className="contact__name">{getContactDisplayName(contact)}</div>
{contact.twitterHandle && <TwitterHandle handle={contact.twitterHandle} />}
</div>
);
}
}
<InlineList elements={contact.keywords}>
{(element, index) => <Keyword keyword={element} key={index} />}
</InlineList>
{twitterBio && <div className="contact__bio">{twitterBio}</div>}
</div>
);
};
Contact.propTypes = contactPropTypes;

export default Contact;
67 changes: 67 additions & 0 deletions src/examples/firstCourse/effects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from 'react';
import ReactDOM from 'react-dom';

const fakeFetch = id =>
new Promise(resolve => {
setTimeout(() => {
resolve({id, name: `Id-${id}`});
}, 1000);
});

const Fetcher = ({id}) => {
const [name, setName] = React.useState(null);
React.useEffect(
() => {
fakeFetch(id).then(response => {
setName(response.name);
});
},
[id]
);

return (
<div>
<span>
Fetcher {id}, name: {name}
</span>
</div>
);
};
const UpdateOnProps = () => {
const [id, setId] = React.useState(0);

return (
<div>
<button onClick={() => setId(id + 1)}>Increment id</button>
<Fetcher id={id} />
</div>
);
};

ReactDOM.render(<UpdateOnProps />, document.getElementById('root'));

const logSize = () => {
console.log(`updating, window size is ${window.innerWidth}`);
};

const ShowWindowSize = () => {
React.useEffect(() => {
window.addEventListener('resize', logSize);
return () => {
window.removeEventListener('resize', logSize);
};
});

return <div>Resize to log the window size</div>;
};
const WithUnMount = () => {
const [hidden, setHidden] = React.useState(false);
return (
<div>
<button onClick={() => setHidden(!hidden)}>Toggle</button>
{hidden && <ShowWindowSize />}
</div>
);
};

// ReactDOM.render(<WithUnMount />, document.getElementById('root'));
Loading

0 comments on commit 0579f1d

Please sign in to comment.