Skip to content
This repository has been archived by the owner on Oct 27, 2022. It is now read-only.

Commit

Permalink
updates to use functional components and hooksx
Browse files Browse the repository at this point in the history
  • Loading branch information
rossmc committed Jan 8, 2020
1 parent 0e1b81a commit 7f4f6b8
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 126 deletions.
66 changes: 31 additions & 35 deletions demo/src/components/Foo/Foo.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Component } from 'react';
import React, { useState, useEffect } from 'react';
import Greeting from './greeting';
import { mergeClasses } from '@magento/venia-ui/lib/classify';
import defaultClasses from './Foo.css';
Expand All @@ -7,45 +7,41 @@ import ProductLink from './productLink';
import { connect } from 'react-redux';
import UpdateRedux from './updateRedux';

class Foo extends Component {
state = {
name: ''
};
const Foo = props => {
const { foo } = props;
const classes = mergeClasses(defaultClasses);
const [nameText, setNameText] = useState('');

componentDidMount() {
useEffect(() => {
document.title = 'Foo Test Page';
}
}, []);

handleChange = (e) => {
this.setState({ name: e.target.value });
function handleChange(e) {
return setNameText(e.target.value);
};

render() {
const classes = mergeClasses(defaultClasses);

return (
<div className={classes.root}>
<h1 className={classes.title}>Foo Component</h1>
<hr className={classes.spacer} />
<p className={classes.label}>A child component with propTypes &amp; CSS Modules:</p>
<Greeting name="Joe Bloggs" className={classes.title} />
<hr className={classes.spacer} />
<p className={classes.label}>A React controlled input element:</p>
<input type="text" value={this.state.name} onChange={this.handleChange} />
<div>{this.state.name}</div>
<hr className={classes.spacer} />
<p className={classes.label}>Reuse of a the PWA Studio component to render a category list:</p>
<CategoryList title="Foo Recommends" id={2} />
<hr className={classes.spacer} />
<p className={classes.label}>A custom React Component using GraphQl &amp; Apollo</p>
<ProductLink sku="VT11" />
<hr className={classes.spacer} />
<p className={classes.label}>The input below is interacting with Redux:</p>
<UpdateRedux test={this.props.foo.test} />
<p style={{ marginTop: 10 }}>{this.props.foo.test}</p>
</div>
);
}
return (
<div className={classes.root}>
<h1 className={classes.title}>Foo Component</h1>
<hr className={classes.spacer} />
<p className={classes.label}>A child component with propTypes &amp; CSS Modules:</p>
<Greeting name="Joe Bloggs" className={classes.title} />
<hr className={classes.spacer} />
<p className={classes.label}>A React controlled input element:</p>
<input type="text" value={nameText} onChange={handleChange} />
<div>{nameText}</div>
<hr className={classes.spacer} />
<p className={classes.label}>Reuse of a the PWA Studio component to render a category list:</p>
<CategoryList title="Foo Recommends" id={2} />
<hr className={classes.spacer} />
<p className={classes.label}>A custom React Component using GraphQl &amp; Apollo</p>
<ProductLink sku="VT11" />
<hr className={classes.spacer} />
<p className={classes.label}>The input below is interacting with Redux:</p>
<UpdateRedux test={foo.test} />
<p style={{ marginTop: 10 }}>{foo.test}</p>
</div>
);
}

const mapStateToProps = ({ foo }) => ({ foo });
Expand Down
26 changes: 13 additions & 13 deletions demo/src/components/Foo/greeting.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React, { Component } from 'react';
import { PropTypes, string } from 'prop-types';
import React from 'react';
import { PropTypes } from 'prop-types';

class Greeting extends Component {
static propTypes = {
name: PropTypes.string
};

render() {
return (
<strong>Hello, {this.props.name}!</strong>
);
}
const Greeting = props => {
const { name } = props;

return (
<strong>Hello, {name}!</strong>
);
}

export default Greeting;
Greeting.propTypes = {
name: PropTypes.string
};

export default Greeting;
28 changes: 13 additions & 15 deletions demo/src/components/Foo/updateRedux.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import React, { Component } from 'react';
import React from 'react';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { PropTypes, func, string } from 'prop-types';
import { PropTypes } from 'prop-types';
import { updateTest } from 'src/actions/foo';

class updateRedux extends Component {
static propTypes = {
test: PropTypes.string,
updateTest: PropTypes.func.isRequired
};
const updateRedux = props => {
const { test, updateTest } = props;

render() {
const { test, updateTest } = this.props;

return (
<input type="text" value={test} onChange={updateTest} style={{ textAlign: 'center' }} />
);
}
return (
<input type="text" value={test} onChange={updateTest} style={{ textAlign: 'center' }} />
);
}

updateRedux.propTypes = {
test: PropTypes.string,
updateTest: PropTypes.func.isRequired
};

const mapDispatchToProps = dispatch => ({
updateTest: (e) => dispatch(updateTest(e.target.value))
});
Expand All @@ -28,4 +26,4 @@ export default compose(
null,
mapDispatchToProps
)
)(updateRedux);
)(updateRedux);
27 changes: 13 additions & 14 deletions doc/add-a-static-route/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,19 @@ export { default } from './Foo';

*src/components/Foo/Foo.js*
```javascript
import React, { Component } from 'react';

class Foo extends Component {


componentDidMount() {
document.title = 'Foo Test Page';
}
render() {
return (
<h1>Hello Foo Component</h1>
);
}
import React, { useEffect } from 'react';

const Foo = () => {

useEffect(() => {
document.title = 'Foo Test Page';
}, []);

return (
<h1>Hello Foo Component</h1>
);
}

export default Foo;
```

Expand All @@ -131,6 +129,7 @@ Browse to the _/foo.html_ URL in the application.

- [Introducing JSX][]
- [Function and Class Components in REACT][]
- [Introducing React Hooks][]

---
- [> see other topics](../../README.md#topics)
Expand Down
31 changes: 20 additions & 11 deletions doc/component-state/index.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
# Component State

We'll create a simple [controlled form element][] for our Foo component to demonstrate how [component state][] is used in React.
We'll create a simple [controlled form element][] for our Foo component to demonstrate how [component state][] is used in React with Hooks.

> controlled form elements are similar to KnockoutJS observables use in Magento2.
{: .bs-callout .bs-callout-info}
controlled form elements are similar to KnockoutJS observables use in Magento2.

In the _Foo.js_ component, first add the [state hook][] to your React `import` statement.

```javascript
import React, { useState, useEffect } from 'react';
```

First add the state object to the Foo component and a function to handle when it changes.

Next, declare nameText variables which will `useState` and a `handleChange` function.

```javascript
class Foo extends Component {
state = {
name: ''
};
const Foo = props => {
const classes = mergeClasses(defaultClasses, props.classes);
const [nameText, setNameText] = useState('');

handleChange = (e) => {
this.setState({ name: e.target.value });
function handleChange(e) {
return setNameText(e.target.value);
};

// other code...
Expand All @@ -22,10 +30,10 @@ class Foo extends Component {
Then add the following JSX:
```jsx
<hr className={classes.spacer}/>
<hr className={classes.spacer} />
<p className={classes.label}>A React controlled input element:</p>
<input type="text" value={this.state.name} onChange={this.handleChange}/>
<div>{this.state.name}</div>
<input type="text" value={nameText} onChange={handleChange} />
<div>{nameText}</div>
```
Now test this element on the storefront and see how it automatically updates as you type into the input element.
Expand All @@ -34,6 +42,7 @@ Now test this element on the storefront and see how it automatically updates as
- [controlled form element][]
- [component state][]
- [Introducing React Hooks][]
---
- [> see other topics](../../README.md#topics)
Expand Down
Binary file modified doc/css-modules/images/css-modules.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 7 additions & 2 deletions doc/css-modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,15 @@ import { mergeClasses } from '@magento/venia-ui/lib/classify';
import defaultClasses from './Foo.css';
```

At the beginning of the _Foo_ components `render()` method, assign the class names from the css file you imported:
At the beginning of the _Foo.js_ component set the `classes` constant with the `mergeClasses` function.

```javascript
const classes = mergeClasses(defaultClasses);
// other code

const Foo = props => {
const classes = mergeClasses(defaultClasses);

// other code
```
The CSS class names can now be added to the JSX with something like:
Expand Down
47 changes: 28 additions & 19 deletions doc/manage-state-with-redux/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,28 @@ Open the _src/components/Foo/Foo.js_ file and add the following import.
import { connect } from 'react-redux';
```

Now replace the export statement with the following:
Now to map the state from redux to your component's `props` replace the export statement with the following:

```javascript
const mapStateToProps = ({ foo }) => ({ foo });
export default connect(mapStateToProps)(Foo);
```

And lets assign `props.foo` to a `foo` constant in the _Foo.js_ component.

```javascript
// other code
const Foo = props => {
const { foo } = props;
const classes = mergeClasses(defaultClasses, props.classes);
const [nameText, setNameText] = useState('');
// other code
```
And add the following to your JSX:
```jsx
<p>{this.props.foo.test}</p>
<p>{foo.test}</p>
```
Browse to _/foo.html_ to see _"lorem ipsum"_ you have added to the redux store.
Expand Down Expand Up @@ -177,27 +188,25 @@ Next we'll create a new child component which will use the action above to updat
_src/components/Foo/updateRedux.js_
```javascript
import React, { Component } from 'react';
import React from 'react';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { PropTypes, func, string } from 'prop-types';
import { PropTypes } from 'prop-types';
import { updateTest } from 'src/actions/foo';

class updateRedux extends Component {
static propTypes = {
test: PropTypes.string,
updateTest: PropTypes.func.isRequired
};
const updateRedux = props => {
const { test, updateTest } = props;

render() {
const { test, updateTest } = this.props;

return (
<input type="text" value={test} onChange={updateTest} style={{ textAlign: 'center' }} />
);
}
return (
<input type="text" value={test} onChange={updateTest} style={{ textAlign: 'center' }} />
);
}

updateRedux.propTypes = {
test: PropTypes.string,
updateTest: PropTypes.func.isRequired
};

const mapDispatchToProps = dispatch => ({
updateTest: (e) => dispatch(updateTest(e.target.value))
});
Expand All @@ -210,7 +219,7 @@ export default compose(
)(updateRedux);
```
Import the above component to the FOO Component.
Import the above component to the _Foo.js_ Component.
```javascript
import UpdateRedux from './updateRedux';
Expand All @@ -221,8 +230,8 @@ And add it to the JSX:
```jsx
<hr className={classes.spacer} />
<p className={classes.label}>The input below is interacting with Redux:</p>
<UpdateRedux test={this.props.foo.test} />
<p style={{ marginTop: 10 }}>{this.props.foo.test}</p>
<UpdateRedux test={foo.test} />
<p style={{ marginTop: 10 }}>{foo.test}</p>
```
Now test it by typing into the new input box while checking Redux dev tools to see the value in the Redux store update.
Expand Down
Loading

0 comments on commit 7f4f6b8

Please sign in to comment.