Skip to content

Commit cf7e849

Browse files
Merge pull request #750 from dustinsoftware/bootstrap-sample
Add reactstrap to samples
2 parents 9d8f9bb + c27c1ba commit cf7e849

File tree

18 files changed

+6474
-1215
lines changed

18 files changed

+6474
-1215
lines changed

src/React.Sample.Mvc4/App_Start/ReactConfig.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public static void Configure()
1919
ReactSiteConfiguration.Configuration
2020
.SetReuseJavaScriptEngines(true)
2121
.SetAllowJavaScriptPrecompilation(true)
22+
.AddScriptWithoutTransform("~/Content/lib/reactstrap.min.js")
2223
.AddScript("~/Content/Sample.jsx");
2324

2425
JsEngineSwitcher.Current.DefaultEngineName = V8JsEngine.EngineName;

src/React.Sample.Mvc4/Content/Sample.jsx

Lines changed: 44 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,87 +7,72 @@
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99

10-
function HooksDemo() {
11-
let [count, updateCount] = React.useState(0);
12-
return (
13-
<button onClick={() => updateCount(count + 1)}>
14-
Click count: {count}
15-
</button>
16-
);
17-
}
18-
19-
class CommentsBox extends React.Component {
20-
static propTypes = {
21-
initialComments: PropTypes.array.isRequired,
22-
page: PropTypes.number,
23-
};
24-
25-
state = {
26-
comments: this.props.initialComments,
27-
page: this.props.page,
10+
function CommentsBox(props) {
11+
let [state, updateState] = React.useState({
12+
comments: props.initialComments,
13+
page: props.page,
2814
hasMore: true,
29-
loadingMore: false,
30-
};
15+
loadingMore: false
16+
});
3117

32-
loadMoreClicked = evt => {
33-
var nextPage = this.state.page + 1;
34-
this.setState({
18+
function loadMoreClicked(evt) {
19+
let nextPage = state.page + 1;
20+
let comments = state.comments;
21+
updateState(prevState => ({
22+
...prevState,
3523
page: nextPage,
36-
loadingMore: true,
37-
});
24+
loadingMore: true
25+
}));
3826

39-
var url = evt.target.href;
40-
var xhr = new XMLHttpRequest();
27+
let url = '/comments/page-' + (state.page + 1);
28+
let xhr = new XMLHttpRequest();
4129
xhr.open('GET', url, true);
4230
xhr.setRequestHeader('Content-Type', 'application/json');
31+
4332
xhr.onload = () => {
44-
var data = JSON.parse(xhr.responseText);
45-
this.setState({
46-
comments: this.state.comments.concat(data.comments),
33+
let data = JSON.parse(xhr.responseText);
34+
updateState(prevState => ({
35+
...prevState,
36+
comments: comments.concat(data.comments),
4737
hasMore: data.hasMore,
48-
loadingMore: false,
49-
});
38+
loadingMore: false
39+
}));
5040
};
5141
xhr.send();
5242
evt.preventDefault();
53-
};
54-
55-
render() {
56-
var commentNodes = this.state.comments.map(comment => (
57-
<Comment author={comment.Author}>{comment.Text}</Comment>
58-
));
59-
60-
return (
61-
<div className="comments">
62-
<HooksDemo />
63-
<h1>Comments</h1>
64-
<ol className="commentList">{commentNodes}</ol>
65-
{this.renderMoreLink()}
66-
</div>
67-
);
6843
}
6944

70-
renderMoreLink = () => {
71-
if (this.state.loadingMore) {
45+
let commentNodes = state.comments.map(comment => (
46+
<Comment author={comment.Author}>{comment.Text}</Comment>
47+
));
48+
49+
function renderMoreLink() {
50+
if (state.loadingMore) {
7251
return <em>Loading...</em>;
73-
} else if (this.state.hasMore) {
52+
} else if (state.hasMore) {
7453
return (
75-
<a
76-
href={'/comments/page-' + (this.state.page + 1)}
77-
onClick={this.loadMoreClicked}
78-
>
54+
<Reactstrap.Button onClick={loadMoreClicked}>
7955
Load More
80-
</a>
56+
</Reactstrap.Button>
8157
);
8258
} else {
8359
return <em>No more comments</em>;
8460
}
85-
};
61+
}
62+
63+
return (
64+
<div className="comments">
65+
<h1>Comments</h1>
66+
<ol className="commentList">{commentNodes}</ol>
67+
{renderMoreLink()}
68+
<hr />
69+
</div>
70+
);
8671
}
8772

8873
class Comment extends React.Component {
8974
static propTypes = {
90-
author: PropTypes.object.isRequired,
75+
author: PropTypes.object.isRequired
9176
};
9277

9378
render() {
@@ -104,7 +89,7 @@ class Comment extends React.Component {
10489

10590
class Avatar extends React.Component {
10691
static propTypes = {
107-
author: PropTypes.object.isRequired,
92+
author: PropTypes.object.isRequired
10893
};
10994

11095
render() {
@@ -114,7 +99,7 @@ class Avatar extends React.Component {
11499
alt={'Photo of ' + this.props.author.Name}
115100
width={50}
116101
height={50}
117-
className="commentPhoto"
102+
className="commentPhoto mr-1"
118103
/>
119104
);
120105
}

src/React.Sample.Mvc4/Content/lib/reactstrap.min.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/React.Sample.Mvc4/React.Sample.Mvc4.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
<ItemGroup>
153153
<Compile Include="App_Start\FilterConfig.cs" />
154154
<Compile Include="App_Start\RouteConfig.cs" />
155+
<Content Include="Content\lib\reactstrap.min.js" />
155156
<Content Include="Content\Sample.css" />
156157
<Content Include="Global.asax" />
157158
<Content Include="Web.config">

src/React.Sample.Mvc4/Views/Home/Index.cshtml

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,29 @@
55
<head>
66
<title>ReactJS.NET Sample</title>
77
<link rel="stylesheet" href="~/Content/Sample.css" />
8+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css" />
89
</head>
910
<body>
10-
<p>
11-
This is an example of ReactJS.NET's server-side rendering. The initial state of this
12-
comments box is rendered server-side, and additional data is loaded via AJAX and rendered
13-
client-side.
14-
</p>
15-
16-
<!-- Render the component server-side, passing initial props -->
17-
@Html.React("CommentsBox", new { initialComments = Model.Comments, page = Model.Page })
18-
19-
<!-- Load all required scripts (React + the site's scripts) -->
20-
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.development.js"></script>
21-
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.development.js"></script>
22-
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
23-
@Scripts.Render("~/bundles/main")
24-
<!-- Render the code to initialise the component -->
25-
@Html.ReactInitJavaScript()
11+
<div class="container">
12+
<div class="jumbotron">
13+
<h1 class="display-4">ASP.NET MVC Sample</h1>
14+
<hr className="my-4" />
15+
<p class="lead">
16+
This is an example of ReactJS.NET's server-side rendering. The initial state of this
17+
comments box is rendered server-side, and additional data is loaded via AJAX and rendered
18+
client-side.
19+
</p>
20+
<!-- Render the component server-side, passing initial props -->
21+
@Html.React("CommentsBox", new { initialComments = Model.Comments, page = Model.Page })
22+
<!-- Load all required scripts (React + the site's scripts) -->
23+
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.development.js"></script>
24+
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.development.js"></script>
25+
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
26+
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/reactstrap/7.1.0/reactstrap.min.js"></script>
27+
@Scripts.Render("~/bundles/main")
28+
<!-- Render the code to initialise the component -->
29+
@Html.ReactInitJavaScript()
30+
</div>
31+
</div>
2632
</body>
2733
</html>
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
{
2-
"presets": ["react", "env"]
2+
"presets": ["@babel/preset-react", "@babel/preset-env"],
3+
"plugins": [
4+
"@babel/proposal-object-rest-spread",
5+
"@babel/proposal-class-properties"
6+
]
37
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (c) 2014-Present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
body {
11+
font-family: Calibri, Verdana, sans-serif;
12+
}
13+
14+
.commentList {
15+
list-style-type: none;
16+
margin: 0;
17+
padding: 0;
18+
}
19+
20+
.commentList li {
21+
border-bottom: 1px solid #999;
22+
padding: 0.5em 0;
23+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* Copyright (c) 2014-Present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
import React from 'react';
11+
import PropTypes from 'prop-types';
12+
import * as Reactstrap from 'reactstrap';
13+
14+
export function CommentsBox(props) {
15+
let [state, updateState] = React.useState({
16+
comments: props.initialComments,
17+
page: props.page,
18+
hasMore: true,
19+
loadingMore: false,
20+
});
21+
22+
function loadMoreClicked(evt) {
23+
let nextPage = state.page + 1;
24+
let comments = state.comments;
25+
updateState(prevState => ({
26+
...prevState,
27+
page: nextPage,
28+
loadingMore: true,
29+
}));
30+
31+
let url = '/comments/page-' + (state.page + 1);
32+
let xhr = new XMLHttpRequest();
33+
xhr.open('GET', url, true);
34+
xhr.setRequestHeader('Content-Type', 'application/json');
35+
36+
xhr.onload = () => {
37+
let data = JSON.parse(xhr.responseText);
38+
updateState(prevState => ({
39+
...prevState,
40+
comments: comments.concat(data.comments),
41+
hasMore: data.hasMore,
42+
loadingMore: false,
43+
}));
44+
};
45+
xhr.send();
46+
evt.preventDefault();
47+
}
48+
49+
let commentNodes = state.comments.map(comment => (
50+
<Comment author={comment.author}>{comment.text}</Comment>
51+
));
52+
53+
function renderMoreLink() {
54+
if (state.loadingMore) {
55+
return <em>Loading...</em>;
56+
} else if (state.hasMore) {
57+
return (
58+
<Reactstrap.Button onClick={loadMoreClicked}>
59+
Load More
60+
</Reactstrap.Button>
61+
);
62+
} else {
63+
return <em>No more comments</em>;
64+
}
65+
}
66+
67+
return (
68+
<div>
69+
<p className="lead">
70+
This is an example of ReactJS.NET's server-side rendering. The
71+
initial state of this comments box is rendered server-side, and
72+
additional data is loaded via AJAX and rendered client-side.
73+
</p>
74+
<div className="comments">
75+
<h1>Comments</h1>
76+
<ol className="commentList">{commentNodes}</ol>
77+
{renderMoreLink()}
78+
<hr />
79+
</div>
80+
</div>
81+
);
82+
}
83+
84+
class Comment extends React.Component {
85+
static propTypes = {
86+
author: PropTypes.object.isRequired,
87+
};
88+
89+
render() {
90+
return (
91+
<li>
92+
<Avatar author={this.props.author} />
93+
<strong>{this.props.author.name}</strong>
94+
{': '}
95+
{this.props.children}
96+
</li>
97+
);
98+
}
99+
}
100+
101+
class Avatar extends React.Component {
102+
static propTypes = {
103+
author: PropTypes.object.isRequired,
104+
};
105+
106+
render() {
107+
return (
108+
<img
109+
src={this.getPhotoUrl(this.props.author)}
110+
alt={'Photo of ' + this.props.author.name}
111+
width={50}
112+
height={50}
113+
className="commentPhoto mr-1"
114+
/>
115+
);
116+
}
117+
118+
getPhotoUrl = author => {
119+
return (
120+
'https://avatars.githubusercontent.com/' +
121+
author.githubUsername +
122+
'?s=50'
123+
);
124+
};
125+
}

0 commit comments

Comments
 (0)