我是redux的新手,我正在尝试重新构建一个旧的应用程序 - 因此第一页将向用户显示可能的启动画面,然后登录表单 - 并且在成功登录时 - 向用户显示主网站。
我想帮助对antd表单和redux处理/处理进行登录验证处理。加强这些演示。类似问题的链接 - 细分等等......可能遇到的常见问题等等 - 甚至可能退回功能。
我有这些旧组件,所以这就是应用程序的外观。我很可能会使用antd作为表单组件。
这是一个我使用redux的演示 - 但这只是从api获取数据 - 然后渲染它 - 我热衷于挑选这部分代码来替换部分表单处理等。
这个redux演示在这个jsfiddle上供参考。
http://jsfiddle.net/0ht35rpb/104/
// redux demo
import React, { Component } from 'react'
import { render } from 'react-dom'
import {Provider, connect} from 'react-redux'
import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk';
import MapChart from './modules/mapChart/MapChart'
import './index.css'
function fetchPostsRequest(){
return {
type: "FETCH_REQUEST"
}
}
function fetchPostsSuccess(payload) {
return {
type: "FETCH_SUCCESS",
payload
}
}
function fetchPostsError() {
return {
type: "FETCH_ERROR"
}
}
const reducer = (state = {}, action) => {
switch (action.type) {
case "FETCH_REQUEST":
return state;
case "FETCH_SUCCESS":
return {...state, posts: action.payload};
default:
return state;
}
}
function fetchPostsWithRedux() {
return (dispatch) => {
dispatch(fetchPostsRequest());
return fetchPosts().then(([response, json]) =>{
if(response.status === 200){
dispatch(fetchPostsSuccess(json))
}
else{
dispatch(fetchPostsError())
}
})
}
}
function fetchPosts() {
const URL = 'https://data.police.uk/api/crimes-street/all-crime?poly=52.268,0.543:52.794,0.238:52.130,0.478&date=2017-01';
return fetch(URL, { method: 'GET'})
.then( response => Promise.all([response, response.json()]));
}
// this is how you'll get your icon links
// instead of a switch with loads of repetitive bytes
const iconMap = {
'anti-social-behaviour': 'green-dot',
'burglary': 'red-dot',
'other-theft': 'pink-dot',
'public-order': 'purple',
'robbery': 'yellow',
'vehicle-crime': 'orange',
'violent-crime': 'orange-dot',
'other-crime': 'ltblue-dot',
'criminal-damage-arson': 'yellow-dot',
'drugs': 'purple-dot',
'shoplifting': 'blue-dot'
}
// this is a class because it needs state
class CrimeMap extends Component {
state = {
markers: []
}
componentDidMount() {
this.props.fetchPostsWithRedux()
}
componentWillReceiveProps(nextProps){
this.setState({markers: this.mapLayerData(nextProps.posts)});
}
// store only the data you want to pass as props to each Marker
// instead of mapping it directly in MapChart every time it renders
mapLayerData(markers) {
// use a standard map function instead of $.each
// destructuring saves time and repetition
return markers.map(({ category, location }) => ({
// use a template string and a simple map of icon names to get your icon uri
icon: 'http://maps.google.com/mapfiles/ms/icons/'+ iconMap[category] +'.png',
label: category,
name: category,
position: {
lat: location.latitude,
lng: location.longitude
}
}))
}
render() {
// there's only one layer, so render it directly
return (
<div className="app">
<MapChart markers={this.state.markers} />
</div>
)
}
}
function mapStateToProps(state){
return {
posts: state.posts
}
}
let Container = connect(mapStateToProps, {fetchPostsWithRedux})(CrimeMap);
const store = createStore(
reducer,
applyMiddleware(thunk)
);
render(
<Provider store={store}>
<Container/>
</Provider>,
document.getElementById('root')
);
这里是带有旧代码的jsfiddle - 如果它有助于证明那里的变化/改进。
http://jsfiddle.net/0ht35rpb/103/
//旧代码
import React from 'react';
import ReactDOM from 'react-dom';
//splash page
var SplashPage = React.createClass({
componentDidMount: function() {
function animateSplash(){
$('.splash-page').animate({
opacity: 0,
}, 2500, "linear", function() {
// Animation complete.
$('.splash-page').hide();
});
}
setTimeout(function(){
animateSplash();
}, 4000);
},
render: function() {
return (
<div className="splash-page">
<div className="content">
<div className="splash">
SPLASH PAGE
</div>
</div>
</div>
);
}
});
//form page
var LandingForm = React.createClass({
componentDidMount: function(){
},
getInitialState: function() {
return {postcode: '', propertytype: '', propertysize: '', propertytypename: '', isValid: false};
},
checkPostCodeValid: function(target, postcode){
var host = this.props.source[0]["local"];
if(window.location.hostname != "localhost"){
host = this.props.source[0]["live"];
}
var isPostcodeValidApiCall = host + 'codeigniter/index.php/api/isPostcodeValid/'+postcode;
//quick hack to bypass email validator on computer with no db
if(window.location.hostname == "localhost"){
isPostcodeValidApiCall = host + "_test_emailvalidate_json1_nw1.php";
}
var that = this;
this.serverRequest = $.get(isPostcodeValidApiCall, function (response) {
var response = JSON.parse(response);
var errorMsg = response.isPostcodeValid.errorMessage;
var isValid = response.isPostcodeValid.isValid;
if(!isValid){
//show error message
setLabelError(target, errorMsg, true);//target, error message, show error
}
else{
//do not show error
setLabelError(target, errorMsg, false);//target, error message, show error
}
that.setState({
isValid: isValid
});
}.bind(this));
},
handlePostcodeChange: function(e) {
this.setState({postcode: e.target.value});
},
handleValidation: function(e){
//do a check on char lengths greater than 1
if((e.target.value).length > 1){
this.checkPostCodeValid(e.target, e.target.value);
}
},
handlePropertyTypeChange: function(val) {
this.setState({propertytypename: val.label});
this.setState({propertytype: val.value});
setReactSelectorLabel(val);
},
handlePropertySizeChange: function(val) {
this.setState({propertysize: val.value});
setReactSelectorLabel(val);
},
handleSubmit: function(e) {
e.preventDefault();
var postcode = this.state.postcode.trim().toUpperCase();
var propertytype = this.state.propertytype.trim();
var propertysize = this.state.propertysize.trim();
var isValid = this.state.isValid;
//console.log("isValid", isValid);
var propertytypename = this.state.propertytypename.trim();
if (!postcode || !propertytype || !propertysize || !isValid) {
return;
}
// TODO: send request to the server
this.setState({postcode: '', propertytype: '', propertysize: '', propertytypename: '', isValid: false});
var shortPostcode = ((postcode.substring(0, postcode.length-3)).trim());
var postCodeSector = ((postcode.substring(0, postcode.length-2)).trim());
//build queries
var masterApiCall = '/api/master/'+shortPostcode+'/'+propertytype+'/'+propertysize;
var directApiCall = '/api/direct/'+postcode;
var dataEntry = [
{
"directApiCall" : directApiCall,
"masterApiCall": masterApiCall,
"postCodeSector": postCodeSector,
"postCode": shortPostcode,
"fullPostCode": postcode,
"propertyType": propertytype,
"propertySize": propertysize,
"propertyTypeName": propertytypename
}
];
ReactDOM.render(
<DataPage root={initConfig} source={dataEntry} />,
document.getElementById('root'),
function() {
//xx
}
);
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
var optionsPropertyType = [
{ value: 'val1', label: 'key1' },
{ value: 'val2', label:'key2'}
];
var optionsPropertySize = [
{ value: 'val1', label: 'key1' },
{ value: 'val2', label:'key2'}
];
return (
<div className="container" data-role="screenbackground">
<div className="row">
<div className="col-md-12 col">
<div className="form-components">
<form id="mainform" data-role="form-aesethetics" className="commentForm" onSubmit={this.handleSubmit}>
<fieldset>
<label>Postcode</label>
<input
placeholder="Postcode"
type="text"
name="postcode"
value={this.state.postcode}
onChange={this.handlePostcodeChange}
onKeyPress={this.handleValidation}
/>
</fieldset>
<fieldset>
<label>Property Type</label>
<Select
name="propertytype"
value={this.state.propertytype}
options= {optionsPropertyType}
onChange={this.handlePropertyTypeChange}
placeholder="Property type"
/>
</fieldset>
<fieldset>
<label>Property Size</label>
<Select
name="propertysize"
value={this.state.propertysize}
options= {optionsPropertySize}
onChange={this.handlePropertySizeChange}
placeholder="Property size"
/>
</fieldset>
<fieldset className="aligninmobile">
<input type="submit" disabled={!this.state.isValid} value="Let's Go"/>
</fieldset>
</form>
</div>
</div>
</div>
</div>
);
}
});
//Data Page
var DataPage = React.createClass({
getInitialState: function() {
return {
rawDirectData: ''
};
},
componentDidMount: function () {
//check host to see which source to use
var host = this.props.root[0]["local"];
if(window.location.hostname != "localhost"){
host = this.props.root[0]["live"];
}
var directApi = host + this.props.source[0]["directApiCall"];
if(window.location.hostname == "localhost"){
directApi = host + "_test_direct_json1_nw1.php";
}
var that = this;
function requestData(source, callback){
that.serverRequest = $.get(source, function (response) {
callback(response);
}.bind(that));
}
requestData(directApi, function(rawDirectData){
that.setState({
rawDirectData: JSON.parse(rawDirectData)
});
});
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
var props = this.props;
var directApiData = this.state.rawDirectData;
return (
<div className="container">
<div className="row">
<div className="col-md-12 col">
<MultipleComponents root={props.root} source={props.source} />
</div>
<div className="col-md-12 col">
<ContactForm root={props.root} source={props.source} data={directApiData}/>
</div>
</div>
</div>
);
}
});
//LandingForm
ReactDOM.render(
<div>
<SplashPage />
<LandingForm source={initConfig} />
</div>,
document.getElementById('root'),
function(){
}
);