Working React+Redux template

This commit is contained in:
SteveSandersonMS
2016-03-07 14:32:36 +00:00
parent ec9337754f
commit cf7a519919
26 changed files with 1475 additions and 131 deletions

View File

@@ -1,30 +1,27 @@
import * as React from 'react';
import { Link } from 'react-router';
import { provide } from 'redux-typed';
import { ApplicationState } from '../store';
import * as CounterStore from '../store/Counter';
interface CounterState {
currentCount: number;
}
export class Counter extends React.Component<any, CounterState> {
constructor() {
super();
this.state = { currentCount: 0 };
}
class Counter extends React.Component<CounterProps, void> {
public render() {
return <div>
<h1>Counter</h1>
<p>This is a simple example of a React component.</p>
<p>Current count: <strong>{ this.state.currentCount }</strong></p>
<p>Current count: <strong>{ this.props.count }</strong></p>
<button onClick={ () => { this.incrementCounter() } }>Increment</button>
<button onClick={ () => { this.props.increment() } }>Increment</button>
</div>;
}
incrementCounter() {
this.setState({
currentCount: this.state.currentCount + 1
});
}
}
// Build the CounterProps type, which allows the component to be strongly typed
const provider = provide(
(state: ApplicationState) => state.counter, // Select which part of global state maps to this component
CounterStore.actionCreators // Select which action creators should be exposed to this component
);
type CounterProps = typeof provider.allProps;
export default provider.connect(Counter);

View File

@@ -1,36 +1,36 @@
import * as React from 'react';
import { Link } from 'react-router';
import { provide } from 'redux-typed';
import { ApplicationState } from '../store';
import * as WeatherForecastsState from '../store/WeatherForecasts';
interface FetchDataExampleState {
forecasts: WeatherForecast[];
loading: boolean;
interface RouteParams {
startDateIndex: string;
}
export class FetchData extends React.Component<any, FetchDataExampleState> {
constructor() {
super();
this.state = { forecasts: [], loading: true };
fetch('/api/SampleData/WeatherForecasts')
.then(response => response.json())
.then((data: WeatherForecast[]) => {
this.setState({ forecasts: data, loading: false });
});
class FetchData extends React.Component<WeatherForecastProps, void> {
componentWillMount() {
// This method runs when the component is first added to the page
let startDateIndex = parseInt(this.props.params.startDateIndex) || 0;
this.props.requestWeatherForecasts(startDateIndex);
}
componentWillReceiveProps(nextProps: WeatherForecastProps) {
// This method runs when incoming props (e.g., route params) change
let startDateIndex = parseInt(nextProps.params.startDateIndex) || 0;
this.props.requestWeatherForecasts(startDateIndex);
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: FetchData.renderForecastsTable(this.state.forecasts);
return <div>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
{ contents }
<p>For more sophisticated applications, consider an architecture such as Redux or Flux for managing state. You can generate an ASP.NET Core application with React and Redux using <code>dotnet new aspnet/spa/reactredux</code> instead of using this template.</p>
<p>This component demonstrates fetching data from the server and working with URL parameters.</p>
{ this.renderForecastsTable() }
{ this.renderPagination() }
</div>;
}
private static renderForecastsTable(forecasts: WeatherForecast[]) {
private renderForecastsTable() {
return <table className='table'>
<thead>
<tr>
@@ -41,7 +41,7 @@ export class FetchData extends React.Component<any, FetchDataExampleState> {
</tr>
</thead>
<tbody>
{forecasts.map(forecast =>
{this.props.forecasts.map(forecast =>
<tr key={ forecast.dateFormatted }>
<td>{ forecast.dateFormatted }</td>
<td>{ forecast.temperatureC }</td>
@@ -52,11 +52,23 @@ export class FetchData extends React.Component<any, FetchDataExampleState> {
</tbody>
</table>;
}
private renderPagination() {
let prevStartDateIndex = this.props.startDateIndex - 5;
let nextStartDateIndex = this.props.startDateIndex + 5;
return <p className='clearfix text-center'>
<Link className='btn btn-default pull-left' to={ `/fetchdata/${ prevStartDateIndex }` }>Previous</Link>
<Link className='btn btn-default pull-right' to={ `/fetchdata/${ nextStartDateIndex }` }>Next</Link>
{ this.props.isLoading ? <span>Loading...</span> : [] }
</p>;
}
}
interface WeatherForecast {
dateFormatted: string;
temperatureC: number;
temperatureF: number;
summary: string;
}
// Build the WeatherForecastProps type, which allows the component to be strongly typed
const provider = provide(
(state: ApplicationState) => state.weatherForecasts, // Select which part of global state maps to this component
WeatherForecastsState.actionCreators // Select which action creators should be exposed to this component
).withExternalProps<{ params: RouteParams }>(); // Also include a 'params' property on WeatherForecastProps
type WeatherForecastProps = typeof provider.allProps;
export default provider.connect(FetchData);

View File

@@ -1,13 +1,13 @@
import * as React from 'react';
export class Home extends React.Component<any, void> {
export default class Home extends React.Component<any, void> {
public render() {
return <div>
<h1>Hello, world!</h1>
<p>Welcome to your new single-page application, built with:</p>
<ul>
<li><a href='https://get.asp.net/'>ASP.NET Core</a> and <a href='https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx'>C#</a> for cross-platform server-side code</li>
<li><a href='https://facebook.github.io/react/'>React</a> and <a href='http://www.typescriptlang.org/'>TypeScript</a> for client-side code</li>
<li><a href='https://facebook.github.io/react/'>React</a>, <a href='http://redux.js.org'>Redux</a>, and <a href='http://www.typescriptlang.org/'>TypeScript</a> for client-side code</li>
<li><a href='https://webpack.github.io/'>Webpack</a> for building and bundling client-side resources</li>
<li><a href='http://getbootstrap.com/'>Bootstrap</a> for layout and styling</li>
</ul>
@@ -18,11 +18,6 @@ export class Home extends React.Component<any, void> {
<li><strong>Hot module replacement</strong>. In development mode, you don't even need to reload the page after making most changes. Within seconds of saving changes to files, rebuilt CSS and React components will be injected directly into your running application, preserving its live state.</li>
<li><strong>Efficient production builds</strong>. In production mode, development-time features are disabled, and the <code>webpack</code> build tool produces minified static CSS and JavaScript files.</li>
</ul>
<h4>Going further</h4>
<p>
For larger applications, or for server-side prerendering (i.e., for <em>isomorphic</em> or <em>universal</em> applications), you should consider using a Flux/Redux-like architecture.
You can generate an ASP.NET Core application with React and Redux using <code>dotnet new aspnet/spa/reactredux</code> instead of using this template.
</p>
</div>;
}
}