基于Redux-Form的React足球投注系统动态表单开发问询
Hey there! Let's walk through how to implement your football betting form with Redux-Form in React, using your existing matches dataset. I'll break this down into actionable steps so you can get up and running quickly.
First, make sure you have all the necessary packages installed. Redux-Form relies on Redux and React-Redux, so run this command in your project directory:
npm install redux-form react-redux redux # or if you use Yarn: yarn add redux-form react-redux redux
You need to add the Redux-Form reducer to your Redux store. Here's how to set that up:
// src/store.js import { createStore, combineReducers } from 'redux'; import { reducer as formReducer } from 'redux-form'; const rootReducer = combineReducers({ // Add your other reducers here if you have them form: formReducer }); export const store = createStore(rootReducer);
Don't forget to wrap your app with the Redux Provider in your root component:
// src/index.js import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { store } from './store'; import BettingForm from './BettingForm'; ReactDOM.render( <Provider store={store}> <BettingForm /> </Provider>, document.getElementById('root') );
Now let's create the form component that handles your matches array. We'll use FieldArray from Redux-Form to dynamically render fields for each match, and Field for individual input fields.
// src/BettingForm.js import React from 'react'; import { reduxForm, Field, FieldArray } from 'redux-form'; // Render a single match's input fields const renderMatch = ({ fields, index, match }) => ( <div className="match-row"> <h4>Match {match.name}</h4> <p>{`Team ${match.home_team} vs Team ${match.away_team}`}</p> {/* Home Result Input */} <div> <label>Home Team Result:</label> <Field name={`matches[${index}].home_result`} type="number" component="input" disabled={match.finished} // Disable if match is already finished /> </div> {/* Away Result Input */} <div> <label>Away Team Result:</label> <Field name={`matches[${index}].away_result`} type="number" component="input" disabled={match.finished} // Disable if match is already finished /> </div> </div> ); // Main form component const BettingForm = ({ handleSubmit, pristine, reset, submitting }) => { // Your existing matches data const initialMatches = [ { name: 1, type: "group", home_team: 1, away_team: 2, home_result: null, away_result: null, date: "2018-06-14T18:00:00+03:00", stadium: 1, channels: [], finished: false }, { name: 2, type: "group", home_team: 3, away_team: 4, home_result: null, away_result: null, date: "2018-06-14T18:00:00+03:00", stadium: 1, channels: [], finished: false } ]; const onSubmit = (values) => { // Handle form submission here - e.g., send to API, update Redux state, etc. console.log('Betting Submissions:', values.matches); // Example: dispatch an action to save bets // dispatch(saveBets(values.matches)); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <h2>Football Betting Form</h2> {/* Render all matches using FieldArray */} <FieldArray name="matches" component={(props) => ( <div> {initialMatches.map((match, index) => ( renderMatch({ ...props, index, match }) ))} </div> )} /> <div className="form-actions"> <button type="submit" disabled={pristine || submitting}> Submit Bets </button> <button type="button" disabled={pristine || submitting} onClick={reset}> Reset </button> </div> </form> ); }; // Connect the form to Redux export default reduxForm({ form: 'bettingForm', // Unique identifier for this form initialValues: { matches: initialMatches // Set initial values from your matches array } })(BettingForm);
If you want to add validation (e.g., ensure results are non-negative numbers), you can define a validation function and pass it to the reduxForm HOC:
const validate = (values) => { const errors = {}; if (values.matches) { values.matches.forEach((match, index) => { if (!match.home_result || match.home_result < 0) { errors.matches = errors.matches || []; errors.matches[index] = { ...errors.matches[index], home_result: 'Enter a valid non-negative score' }; } if (!match.away_result || match.away_result < 0) { errors.matches = errors.matches || []; errors.matches[index] = { ...errors.matches[index], away_result: 'Enter a valid non-negative score' }; } }); } return errors; }; // Update the reduxForm HOC to include validation export default reduxForm({ form: 'bettingForm', initialValues: { matches: initialMatches }, validate })(BettingForm);
Then modify the renderMatch function to display errors:
const renderMatch = ({ fields, index, match, meta: { touched, error } }) => ( <div className="match-row"> {/* ... existing code ... */} {touched && error && <span className="error">{error}</span>} </div> );
- Disabled Fields: The example disables inputs for finished matches - adjust this logic based on your needs.
- Dynamic Updates: If your
matchesarray changes after the form loads (e.g., new matches added), you'll need to update theinitialValuesor usechangeaction from Redux-Form to sync the form state. - Styling: Add CSS classes (like
.match-row,.error,.form-actions) to style the form to match your app's design.
内容的提问来源于stack exchange,提问作者Fernando Maymone

