2015-12-14 5 views
14

आधिकारिक पृष्ठों पर और redux-form के लिए GitHub मुद्दों में वहाँ कैसे initialValues ​​के साथ काम करने के एक से अधिक उदाहरण हैं के रूप में async स्रोत के आधार पर initialValues ​​स्थापित करने के लिए कैसे लेकिन मैं एक नहीं मिल सकता है एक ऐसा जो कि प्रारंभिक वैल्यू को एसिंक्रोनस स्रोत के जवाब में सेट किया जा सकता है, यह समझाने पर केंद्रित है।ऐसे redux-फार्म के साथ एक ajax कॉल

मेरे पास जो मुख्य मामला है, वह एक साधारण सीआरयूडी अनुप्रयोग की तरह है जहां कोई उपयोगकर्ता पहले से मौजूद कुछ इकाई को संपादित करने जा रहा है। जब दृश्य पहली बार खोला जाता है और रेडक्स-फॉर्म घटक घुड़सवार होता है लेकिन घटक को प्रस्तुत करने से पहले प्रारंभिक वैल्यू सेट किया जाना चाहिए। आइए कहें कि इस उदाहरण में जब डेटा पहली बार घुड़सवार होता है और पहली बार प्रस्तुत किया जाता है तो डेटा मांग पर लोड होता है। उदाहरण हार्ड कोडित मानों या रेडक्स स्टोर स्थिति के आधार पर प्रारंभिक वैल्यू सेट करते हैं, लेकिन कोई भी नहीं जिसे मैं XHR या fetch को कॉल की तरह कुछ async के आधार पर प्रारंभिक वैल्यू सेट करने के तरीके पर ध्यान केंद्रित कर सकता हूं।

मुझे यकीन है कि मुझे कुछ मौलिक याद आ रहा है, इसलिए कृपया मुझे सही दिशा में इंगित करें।

संदर्भ:

उत्तर

2

आप componentWillMount() पर प्रेषण आग सकता है, और लदान के लिए राज्य की स्थापना की।

हालांकि यह लोड हो रहा है, उदाहरण के लिए एक स्पिनर प्रस्तुत करें और केवल तभी जब अनुरोध मानों के साथ आता है, राज्य को अद्यतन करें, और फिर मानों के साथ फ़ॉर्म को फिर से प्रस्तुत करें ??

8

संपादित करें:। ReduxForm डॉक्स से अपडेट किया गया समाधान

यह अब है [दस्तावेज] ((http://redux-form.com/6.0.0-alpha.4/examples/initializeFromState/) ReduxForm के नवीनतम संस्करण, और

मेरे पिछले जवाब तुलना में बहुत सरल है में महत्वपूर्ण है connect आपके प्रपत्र घटक को ReduxForm साथ यह सजा के बाद। तो फिर तुम सिर्फ अपने घटक पर किसी भी अन्य प्रोप की तरह initialValues प्रोप उपयोग करने में सक्षम हो जाएगा।

// Decorate with reduxForm(). It will read the initialValues prop provided by connect() 
InitializeFromStateForm = reduxForm({ 
    form: 'initializeFromState' 
})(InitializeFromStateForm) 

// now set initialValues using data from your store state 
InitializeFromStateForm = connect(
    state => ({ 
    initialValues: state.account.data 
    }) 
)(InitializeFromStateForm) 

मैंने इसे रेडक्स-फॉर्म reducer plugin विधि का उपयोग करके पूरा किया।

निम्नलिखित डेमो एसिंक डेटा लाने और प्रतिक्रिया के साथ उपयोगकर्ता फ़ॉर्म को पूर्व-पॉप्युलेट करने वाले निम्नलिखित डेमो।

const RECEIVE_USER = 'RECEIVE_USER'; 

// once you've received data from api dispatch action 
const receiveUser = (user) => { 
    return { 
     type: RECEIVE_USER, 
     payload: { user } 
    } 
} 

// here is your async request to retrieve user data 
const fetchUser = (id) => dispatch => { 
    return fetch('http://getuser.api') 
      .then(response => response.json()) 
      .then(json => receiveUser(json)); 
} 

फिर अपने जड़ कम करने में जहाँ आप अपने redux-form कम करने आपको लगता है कि वापस आ प्राप्त किए गए डेटा के साथ प्रपत्र मूल्यों को ओवरराइड करता है अपने कम करने प्लगइन को शामिल किया जाएगा शामिल हैं।

const formPluginReducer = { 
    form: formReducer.plugin({ 
     // this would be the name of the form you're trying to populate 
     user: (state, action) => { 
     switch (action.type) { 
      case RECEIVE_USER: 
       return { 
        ...state, 
        values: { 
         ...state.values, 
         ...action.payload.user 
        } 
       } 
      default: 
       return state; 
     } 
     } 
    }) 
}; 

const rootReducer = combineReducers({ 
    ...formPluginReducer, 
    ...yourOtherReducers 
}); 

अंत में आप अपने ऐप में अन्य रेड्यूसर के साथ अपना नया फॉर्म रेड्यूसर जोड़ते हैं।

नोट निम्नलिखित मानते हैं कि प्राप्त उपयोगकर्ता ऑब्जेक्ट की चाबियाँ उपयोगकर्ता के रूप में फ़ील्ड के नाम से मेल खाते हैं। यदि ऐसा नहीं है तो आपको फ़ील्ड को मैप करने के लिए डेटा पर एक अतिरिक्त कदम उठाने की आवश्यकता होगी।

+0

यह मेरे लिए काम किया, हालांकि यह एक बुनियादी ऑपरेशन के लिए बॉयलरप्लेट का एक बहुत की तरह लगता है। नोट करें प्लगइन reducer ('मूल्य' वस्तु युक्त) से लौटा राज्य का आकार महत्वपूर्ण है। – ChidG

+1

@ChidG मैंने अपने उत्तर को एक अद्यतन समाधान के साथ अद्यतन किया है जिसे मैंने हाल ही में नवीनतम रेडक्स-फॉर्म दस्तावेज़ों में पाया है। बहुत कम बॉयलर प्लेट, और अधिक सीधे आगे waaayay। – ryandrewjohnson

+0

धन्यवाद - मैंने उस दस्तावेज विधि को आजमाया है, हालांकि मैं इसे काम नहीं कर सका। मैं अभी के लिए 'formReducer.plugin' समाधान के साथ रहूंगा। – ChidG

3

डिफ़ॉल्ट रूप से, आप केवल प्रारंभिक वैल्यू के माध्यम से एक फॉर्म घटक प्रारंभ कर सकते हैं। नए "प्रिस्टिन" मानों के साथ फॉर्म घटक को दोबारा शुरू करने के दो तरीके हैं:

एक सक्षम पास करें प्रोप या रेनक्सफॉर्म() कॉन्फ़िगरेशन पैरामीटर को सही करने के लिए सेट करें ताकि फॉर्म को प्रारंभिक वैल्यूज़ प्रोप के हर बार "प्रिस्टिन" मानों के साथ पुन: प्रारंभ करने की अनुमति दी जा सके। परिवर्तन। इसे फिर से शुरू होने पर गंदे रूप मानों को रखने के लिए, आप KeepDirtyOnReinitialize को सत्य पर सेट कर सकते हैं। डिफ़ॉल्ट रूप से, फ़ॉर्म को पुन: प्रारंभ करने से सभी गंदे मानों को "प्रिस्टिन" मानों से बदल दिया जाता है।

प्रारंभिक कार्रवाई को डिस्पैच करें (रेडक्स-फॉर्म द्वारा प्रदान किए गए क्रिया निर्माता का उपयोग करके)।

से संदर्भित http://redux-form.com/6.1.1/examples/initializeFromState/

0

इस विधि का सबसे अच्छा समाधान नहीं हो सकता है, यह मेरी जरूरतों के लिए काफी अच्छी तरह से काम करता है:

    प्रवेश पर एपीआई के
  • AJAX अनुरोध
  • initializes डेटा जब साथ फार्म अनुरोध पूरा हो गया है या एक सर्वर त्रुटि प्रदर्शित करता है
  • प्रपत्र रीसेट करना अभी भी प्रारंभिक बीज डेटा
  • पर रीसेट हो जाएगा अन्य उद्देश्यों के लिए sed (उदाहरण के लिए, एक साधारण अगर कथन प्रारंभिक मानों को सेट कर सकता है): पोस्ट जोड़ें और पोस्ट संपादित करें या टिप्पणी जोड़ें और टिप्पणी संपादित करें ... आदि।
  • डाटा बाहर निकलने पर Redux रूप से निकाल दिया जाता (Redux में नए डाटा स्टोर करने का कोई कारण नहीं है, क्योंकि यह किया जा रहा एक ब्लॉग घटक के द्वारा पुन: प्रदान की गई है)

Form.jsx:

import React, { Component } from 'react'; 
import { Field, reduxForm } from 'redux-form'; 
import { connect } from 'react-redux'; 
import { browserHistory, Link } from 'react-router'; 

import { editPost, fetchPost } from '../../actions/BlogActions.jsx'; 
import NotFound from '../../components/presentational/notfound/NotFound.jsx'; 
import RenderAlert from '../../components/presentational/app/RenderAlert.jsx'; 
import Spinner from '../../components/presentational/loaders/Spinner.jsx'; 

// form validation checks 
const validate = (values) => { 
    const errors = {} 
    if (!values.title) { 
    errors.title = 'Required'; 
    } 

    if (!values.image) { 
    errors.image = 'Required'; 
    } 

    if (!values.description) { 
    errors.description = 'Required'; 
    } else if (values.description.length > 10000) { 
    errors.description = 'Error! Must be 10,000 characters or less!'; 
    } 

    return errors; 
} 

// renders input fields 
const renderInputField = ({ input, label, type, meta: { touched, error } }) => (
    <div> 
    <label>{label}</label> 
    <div> 
     <input {...input} className="form-details complete-expand" placeholder={label} type={type}/> 
     {touched && error && <div className="error-handlers "><i className="fa fa-exclamation-triangle" aria-hidden="true"></i> {error}</div>} 
    </div> 
    </div> 
) 

// renders a text area field 
const renderAreaField = ({ textarea, input, label, type, meta: { touched, error } }) => (
    <div> 
    <label>{label}</label> 
    <div> 
     <textarea {...input} className="form-details complete-expand" placeholder={label} type={type}/> 
     {touched && error && <div className="error-handlers"><i className="fa fa-exclamation-triangle" aria-hidden="true"></i> {error}</div>} 
    </div> 
    </div> 
) 

class BlogPostForm extends Component { 
    constructor() { 
    super(); 

    this.state = { 
     isLoaded: false, 
     requestTimeout: false, 
    }; 
    } 

    componentDidMount() { 
    if (this.props.location.query.postId) { 
     // sets a 5 second server timeout 
     this.timeout = setInterval(this.timer.bind(this), 5000); 
     // AJAX request to API 
     fetchPost(this.props.location.query.postId).then((res) => { 
     // if data returned, seed Redux form 
     if (res.foundPost) this.initializeForm(res.foundPost); 
     // if data present, set isLoaded to true, otherwise set a server error 
     this.setState({ 
      isLoaded: (res.foundPost) ? true : false, 
      serverError: (res.err) ? res.err : '' 
     }); 
     }); 
    } 
    } 

    componentWillUnmount() { 
    this.clearTimeout(); 
    } 

    timer() { 
    this.setState({ requestTimeout: true }); 
    this.clearTimeout(); 
    } 

    clearTimeout() { 
    clearInterval(this.timeout); 
    } 

    // initialize Redux form from API supplied data 
    initializeForm(foundPost) { 

    const initData = { 
     id: foundPost._id, 
     title: foundPost.title, 
     image: foundPost.image, 
     imgtitle: foundPost.imgtitle, 
     description: foundPost.description 
    } 

    this.props.initialize(initData); 
    } 

    // onSubmit => take Redux form props and send back to server 
    handleFormSubmit(formProps) { 
    editPost(formProps).then((res) => { 
     if (res.err) { 
     this.setState({ 
      serverError: res.err 
     }); 
     } else { 
     browserHistory.push(/blog); 
     } 
    }); 
    } 

    renderServerError() { 
    const { serverError } = this.state; 
    // if form submission returns a server error, display the error 
    if (serverError) return <RenderAlert errorMessage={serverError} /> 
    } 

    render() { 
    const { handleSubmit, pristine, reset, submitting, fields: { title, image, imgtitle, description } } = this.props; 
    const { isLoaded, requestTimeout, serverError } = this.state; 

    // if data hasn't returned from AJAX request, then render a spinner 
    if (this.props.location.query.postId && !isLoaded) { 
     // if AJAX request returns an error or request has timed out, show NotFound component 
     if (serverError || requestTimeout) return <NotFound /> 

     return <Spinner /> 
    } 

    // if above conditions are met, clear the timeout, otherwise it'll cause the component to re-render on timer's setState function 
    this.clearTimeout(); 

    return (
     <div className="col-sm-12"> 
     <div className="form-container"> 
      <h1>Edit Form</h1> 
      <hr /> 
      <form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}> 
      <Field name="title" type="text" component={renderInputField} label="Post Title" /> 
      <Field name="image" type="text" component={renderInputField} label="Image URL" /> 
      <Field name="imgtitle" component={renderInputField} label="Image Description" /> 
      <Field name="description" component={renderAreaField} label="Description" /> 
      <div> 
       <button type="submit" className="btn btn-primary partial-expand rounded" disabled={submitting}>Submit</button> 
       <button type="button" className="btn btn-danger partial-expand rounded f-r" disabled={ pristine || submitting } onClick={ reset }>Clear Values</button> 
      </div> 
      </form> 
     { this.renderServerError() } 
     </div> 
     </div> 
    ) 
    } 
} 

BlogPostForm = reduxForm({ 
    form: 'BlogPostForm', 
    validate, 
    fields: ['name', 'image', 'imgtitle', 'description'] 
})(BlogPostForm); 


export default BlogPostForm = connect(BlogPostForm); 

BlogActions.jsx:

import * as app from 'axios'; 

const ROOT_URL = 'http://localhost:3001'; 

// submits Redux form data to server 
export const editPost = ({ id, title, image, imgtitle, description, navTitle }) => { 
return app.put(`${ROOT_URL}/post/edit/${id}?userId=${config.user}`, { id, title, image, imgtitle, description, navTitle }, config) 
.then(response => { 
    return { success: response.data.message } 
    }) 
    .catch(({ response }) => { 
    if(response.data.deniedAccess) { 
     return { err: response.data.deniedAccess } 
    } else { 
     return { err: response.data.err } 
    } 
    }); 
} 

// fetches a single post from the server for front-end editing  
export const fetchPost = (id) => { 
    return app.get(`${ROOT_URL}/posts/${id}`) 
    .then(response => { 
    return { foundPost: response.data.post} 
    }) 
    .catch(({ response }) => { 
    return { err: response.data.err }; 
    }); 
}  

RenderAlert .jsx:

import React, { Component } from 'react'; 

const RenderAlert = (props) => { 
    const displayMessage =() => { 
     const { errorMessage } = props; 

     if (errorMessage) { 
     return (
      <div className="callout-alert"> 
      <p> 
       <i className="fa fa-exclamation-triangle" aria-hidden="true"/> 
       <strong>Error! </strong> { errorMessage } 
      </p> 
      </div> 
     ); 
     } 
    } 

    return (
     <div> 
     { displayMessage() } 
     </div> 
    ); 
    } 


export default RenderAlert; 

Reducers.jsx

import { routerReducer as routing } from 'react-router-redux'; 
import { reducer as formReducer } from 'redux-form'; 
import { combineReducers } from 'redux'; 

const rootReducer = combineReducers({ 
    form: formReducer, 
    routing 
}); 

export default rootReducer; 
संबंधित मुद्दे